library(here)
library(cowplot)
source(here("utils/data_processing.R"))
source(here("utils/figures.R"))
all_models <- list.files(here("data/processed_diagnoses"), pattern = "gz$") %>%
str_split("diagnoses_|_icd|.csv") %>%
sapply(., function(x) x[2]) %>%
unique()
all_models
[1] "claude-3-haiku-20240307_t1-0" "claude-3-opus-20240229_t1-0" "gemini-1.0-pro-002_t1-0" "gemini-1.5-flash-preview-0514_t1-0" "gemini-1.5-pro-001_t1-0"
[6] "gpt-3.5-turbo-1106" "gpt-4-turbo-preview"
Import data
df_gpt3.5 <- read_model("gpt-3.5-turbo-1106", icd = FALSE)
df_gpt4.0 <- read_model("gpt-4-turbo-preview", icd = FALSE)
df_claude3_haiku_t1.0 <- read_model("claude-3-haiku-20240307_t1-0", icd = FALSE)
df_claude3_opus_t1.0 <- read_model("claude-3-opus-20240229_t1-0", icd = FALSE)
df_gemini1.0_pro_t1.0 <- read_model("gemini-1.0-pro-002_t1-0", icd = FALSE)
df_gemini1.5_pro_t1.0 <- read_model("gemini-1.5-pro-001_t1-0", icd = FALSE)
df_gpt3.5_icd <- read_model("gpt-3.5-turbo-1106", icd = TRUE)
df_gpt4.0_icd <- read_model("gpt-4-turbo-preview", icd = TRUE)
df_claude3_haiku_t1.0_icd <- read_model("claude-3-haiku-20240307_t1-0", icd = TRUE)
df_claude3_opus_t1.0_icd <- read_model("claude-3-opus-20240229_t1-0", icd = TRUE)
df_gemini1.0_pro_t1.0_icd <- read_model("gemini-1.0-pro-002_t1-0", icd = TRUE)
df_gemini1.5_pro_t1.0_icd <- read_model("gemini-1.5-pro-001_t1-0", icd = TRUE)
Rank abundance
Original responses
rank_abundance_plot(df_gpt3.5)+ggtitle("ChatGPT 3.5")

rank_abundance_plot(df_gpt4.0)+ggtitle("ChatGPT 4.0")

rank_abundance_plot(df_claude3_haiku_t1.0)+ggtitle("Claude3 Haiku t1.0")

rank_abundance_plot(df_claude3_opus_t1.0)+ggtitle("Claude3 Opus")

rank_abundance_plot(df_gemini1.0_pro_t1.0)+ggtitle("Gemini 1.0 Pro")

rank_abundance_plot(df_gemini1.5_pro_t1.0)+ggtitle("Gemini 1.5 Pro")

ICD converted responses
rank_abundance_plot(df_gpt3.5_icd)+ggtitle("ChatGPT 3.5 ICD")

rank_abundance_plot(df_gpt4.0_icd)+ggtitle("ChatGPT 4.0 ICD")

rank_abundance_plot(df_claude3_haiku_t1.0_icd)+ggtitle("Claude3 Haiku ICD")

rank_abundance_plot(df_claude3_opus_t1.0_icd)+ggtitle("Claude3 Opus ICD")

rank_abundance_plot(df_gemini1.0_pro_t1.0_icd)+ggtitle("Gemini 1.0 Pro ICD")

rank_abundance_plot(df_gemini1.5_pro_t1.0_icd)+ggtitle("Gemini 1.5 Pro ICD")

Combined model data
multi_ranked_abundance_plot(df_gpt3.5, df_gpt4.0, df_claude3_haiku_t1.0,
df_claude3_opus_t1.0, df_gemini1.0_pro_t1.0,
df_gemini1.5_pro_t1.0)+
ggtitle("Combined model rank abundance", "Original responses")

multi_ranked_abundance_plot(df_gpt3.5_icd, df_gpt4.0_icd, df_claude3_haiku_t1.0_icd,
df_claude3_opus_t1.0_icd, df_gemini1.0_pro_t1.0_icd,
df_gemini1.5_pro_t1.0_icd)+
ggtitle("Combined model rank abundance", "ICD converted responses")

Top diagnoses plots
custom_labeler <- function(x, wrap_width=33) {
x %>%
str_replace("___.+$", "") %>%
str_wrap(width = wrap_width)
}
custom_text_formatting <- list(
theme(axis.text = element_text(size = 7, lineheight = 0.7),
strip.text = element_text(size = 7),
axis.title = element_text(size = 9)),
tidytext::scale_x_reordered(labels = ~custom_labeler(., wrap_width = 45))
)
n_diag <- 25
sub <- "Original responses"
top_diagnosis_plot(df_gpt3.5, n_diag = n_diag)+ggtitle("ChatGPT 3.5", sub)

top_diagnosis_plot(df_gpt4.0, n_diag = n_diag)+ggtitle("ChatGPT 4.0", sub)

top_diagnosis_plot(df_claude3_haiku_t1.0, n_diag = n_diag)+ggtitle("Claude3 Haiku t1.0", sub)

top_diagnosis_plot(df_claude3_opus_t1.0, n_diag = n_diag)+ggtitle("Claude3 Opus t1.0", sub)

top_diagnosis_plot(df_gemini1.0_pro_t1.0, n_diag = n_diag)+ggtitle("Gemini 1.0 Pro", sub)

top_diagnosis_plot(df_gemini1.5_pro_t1.0, n_diag = n_diag)+ggtitle("Gemini 1.5 Pro", sub)

n_diag <- 25
sub <- "ICD converted responses"
top_diagnosis_plot(df_gpt3.5_icd, n_diag = n_diag) + custom_text_formatting + ggtitle("ChatGPT 3.5 ICD", sub)
Scale for x is already present.
Adding another scale for x, which will replace the existing scale.

top_diagnosis_plot(df_gpt4.0_icd, n_diag = n_diag)+ custom_text_formatting+ggtitle("ChatGPT 4.0 ICD", sub)
Scale for x is already present.
Adding another scale for x, which will replace the existing scale.

top_diagnosis_plot(df_claude3_haiku_t1.0_icd, n_diag = n_diag)+ custom_text_formatting+ggtitle("Claude3 Haiku t1.0 ICD", sub)
Scale for x is already present.
Adding another scale for x, which will replace the existing scale.

top_diagnosis_plot(df_claude3_opus_t1.0_icd, n_diag = n_diag)+ custom_text_formatting+ggtitle("Claude3 Opus t1.0 ICD", sub)
Scale for x is already present.
Adding another scale for x, which will replace the existing scale.

top_diagnosis_plot(df_gemini1.0_pro_t1.0_icd, n_diag = n_diag)+ custom_text_formatting+ggtitle("Gemini 1.0 Pro ICD", sub)
Scale for x is already present.
Adding another scale for x, which will replace the existing scale.

top_diagnosis_plot(df_gemini1.5_pro_t1.0_icd, n_diag = n_diag)+ custom_text_formatting+ggtitle("Gemini 1.5 Pro ICD", sub)
Scale for x is already present.
Adding another scale for x, which will replace the existing scale.

multi_top_diagnosis_plot(distribution_vis = "points", wrap_width=45, n_diag = 25,
df_gpt3.5, df_gpt4.0, df_claude3_haiku_t1.0,
df_claude3_opus_t1.0, df_gemini1.0_pro_t1.0,
df_gemini1.5_pro_t1.0)

plt_diag_icd <- multi_top_diagnosis_plot(distribution_vis = "points", wrap_width = 33, n_diag = 15,
df_gpt3.5_icd, df_gpt4.0_icd, df_claude3_haiku_t1.0_icd,
df_claude3_opus_t1.0_icd, df_gemini1.0_pro_t1.0_icd,
df_gemini1.5_pro_t1.0_icd) +
guides(size = guide_legend(override.aes = list(size = 2)))
plt_diag_icd

plt_diag_icd$data %>%
summarise(freq=mean(freq),.by=c("criteria","diagnosis")) %>%
arrange(criteria, desc(freq))
Cumulative top frequency plots
sub <- "Original responses"
cumulative_frequency_plot(df_gpt3.5)$plot+ggtitle("GPT3", sub)

cumulative_frequency_plot(df_gpt4.0)$plot+ggtitle("GPT4", sub)

cumulative_frequency_plot(df_claude3_haiku_t1.0)$plot+ggtitle("Claude3 Haiku", sub)

cumulative_frequency_plot(df_claude3_opus_t1.0)$plot+ggtitle("Claude3 Haiku", sub)

cumulative_frequency_plot(df_gemini1.0_pro_t1.0)$plot+ggtitle("Gemini Pro 1.0", sub)

cumulative_frequency_plot(df_gemini1.5_pro_t1.0)$plot+ggtitle("Gemini Pro 1.5", sub)

sub <- "ICD converted responses"
cumulative_frequency_plot(df_gpt3.5_icd)$plot+ggtitle("GPT3 ICD", sub)

cumulative_frequency_plot(df_gpt4.0_icd)$plot+ggtitle("GPT4 ICD", sub)

cumulative_frequency_plot(df_claude3_haiku_t1.0_icd)$plot+ggtitle("Claude3 Haiku ICD", sub)

cumulative_frequency_plot(df_claude3_opus_t1.0_icd)$plot+ggtitle("Claude3 Haiku ICD", sub)

cumulative_frequency_plot(df_gemini1.0_pro_t1.0_icd)$plot+ggtitle("Gemini Pro 1.0 ICD", sub)

cumulative_frequency_plot(df_gemini1.5_pro_t1.0_icd)$plot+ggtitle("Gemini Pro 1.0 ICD", sub)

plt_freq <- multi_cumulative_frequency_plot(
n_diagnoses = 25,
distribution_vis = "points",
df_gpt3.5,
df_gpt4.0,
df_claude3_haiku_t1.0,
df_claude3_opus_t1.0,
df_gemini1.0_pro_t1.0,
df_gemini1.5_pro_t1.0
) +
ggtitle("Original responses")
plt_freq

plt_freq$data %>% summarise(freq = mean(total_frequency), .by = "criteria")
plt_freq_icd <- multi_cumulative_frequency_plot(
n_diagnoses = 25,
distribution_vis = "points",
df_gpt3.5_icd,
df_gpt4.0_icd,
df_claude3_haiku_t1.0_icd,
df_claude3_opus_t1.0_icd,
df_gemini1.0_pro_t1.0_icd,
df_gemini1.5_pro_t1.0_icd
) +
ggtitle("ICD converted responses")
plt_freq_icd

plt_freq_icd$data %>% summarise(freq = mean(total_frequency), .by = "criteria")
Diagnosis rank table
diagnosis_rank_table(df_gpt3.5, "mast |mastoc|anaphylaxis") %>% mutate(diagnosis = substr(diagnosis, 1, 60))
diagnosis_rank_table(df_gpt4.0, "mast |mastoc|anaphylaxis") %>% mutate(diagnosis = substr(diagnosis, 1, 60))
diagnosis_rank_table(df_claude3_haiku_t1.0, "mast |mastoc|anaphylaxis") %>% mutate(diagnosis = substr(diagnosis, 1, 60))
diagnosis_rank_table(df_claude3_opus_t1.0, "mast |mastoc|anaphylaxis") %>% mutate(diagnosis = substr(diagnosis, 1, 60))
diagnosis_rank_table(df_gemini1.0_pro_t1.0, "mast |mastoc|anaphylaxis") %>% mutate(diagnosis = substr(diagnosis, 1, 60))
diagnosis_rank_table(df_gemini1.5_pro_t1.0, "mast |mastoc|anaphylaxis") %>% mutate(diagnosis = substr(diagnosis, 1, 60))
diagnosis_rank_table(df_gpt3.5_icd, "mast |mastoc|anaphylaxis") %>% mutate(diagnosis = substr(diagnosis, 1, 60))
diagnosis_rank_table(df_gpt4.0_icd, "mast |mastoc|anaphylaxis") %>% mutate(diagnosis = substr(diagnosis, 1, 60))
diagnosis_rank_table(df_claude3_haiku_t1.0_icd, "mast |mastoc|anaphylaxis") %>% mutate(diagnosis = substr(diagnosis, 1, 60))
diagnosis_rank_table(df_claude3_opus_t1.0_icd, "mast |mastoc|anaphylaxis") %>% mutate(diagnosis = substr(diagnosis, 1, 60))
diagnosis_rank_table(df_gemini1.0_pro_t1.0_icd, "mast |mastoc|anaphylaxis") %>% mutate(diagnosis = substr(diagnosis, 1, 60))
diagnosis_rank_table(df_gemini1.5_pro_t1.0_icd, "mast |mastoc|anaphylaxis") %>% mutate(diagnosis = substr(diagnosis, 1, 60))
multi_diagnosis_rank_table <- function(search_pattern, ...){
listN(...) %>%
lapply(., diagnosis_rank_table, pattern = search_pattern) %>%
mapply(function(x,y) {mutate(x, model=y)}, ., names(.), SIMPLIFY = F) %>%
bind_rows() %>%
pivot_longer(contains(c("mcas","kawasaki","sle","migraine")), names_to = "criteria", values_to = "rank") %>%
filter(grepl("mcas", criteria)) %>%
format_models() %>%
format_criteria() %>%
pivot_wider(names_from = "model", values_from = "rank",names_prefix = "model_") %>%
rowwise() %>%
mutate(mean_rank = round(mean(c_across(contains("model_")), na.rm=T)), 0) %>%
mutate(ranks = paste(c_across(contains("model_")), collapse = ", ")) %>%
mutate(output = str_glue("{mean_rank}\n[{ranks}]")) %>%
select(Diagnosis = diagnosis, criteria, output) %>%
pivot_wider(names_from = "criteria", values_from = "output")
}
rank_table <- multi_diagnosis_rank_table(search_pattern = "T78\\.2 |D47\\.02 |D89\\.41 |D89\\.49 |D89\\.4 ",
df_gpt3.5_icd, df_gpt4.0_icd, df_claude3_haiku_t1.0_icd, df_claude3_opus_t1.0_icd, df_gemini1.0_pro_t1.0_icd, df_gemini1.5_pro_t1.0_icd)
rank_table
rank_table %>%
flextable() %>%
width(width = 30) %>%
align(j = 2:3, align = "center", part = "all")
Diagnosis | MCAS - Consortium | MCAS - Alternative |
|---|
T78.2 Anaphylactic shock, unspecified | 1 [1, 1, 1, 1, 1, 1] | 132 [216, 87, 99, 174, 141, 77] |
D47.02 Systemic mastocytosis | 9 [22, 8, 7, 2, 14, 2] | 50 [92, 78, 25, 41, 46, 19] |
D89.41 Monoclonal mast cell activation syndrome | 70 [128, 22, 28, 11, 179, 51] | 74 [141, 64, 22, 37, 168, 12] |
D89.49 Other mast cell activation disorder | 234 [308, 62, 101, 140, 478, 318] | 625 [1155, 568, 178, 467, 1109, 275] |
D89.4 Mast cell activation syndrome and related disorders | 496 [726, 174, NA, NA, 605, 478] | 1423 [NA, 833, 1850, 1594, 1906, 933] |
Diversity
multi_shannon_plot(
distribution_vis = "points",
wrap_width = 45,
n_diag = 25,
df_gpt3.5,
df_gpt4.0,
df_claude3_haiku_t1.0,
df_claude3_opus_t1.0,
df_gemini1.0_pro_t1.0,
df_gemini1.5_pro_t1.0
)

plt_div_icd <- multi_shannon_plot(
distribution_vis = "points",
wrap_width = 45,
n_diag = 25,
df_gpt3.5_icd,
df_gpt4.0_icd,
df_claude3_haiku_t1.0_icd,
df_claude3_opus_t1.0_icd,
df_gemini1.0_pro_t1.0_icd,
df_gemini1.5_pro_t1.0_icd
)
plt_div_icd

plt_div_icd$data %>% summarise(shannon=mean(shannon),.by="criteria")
extract_ggpubr_pvalues(plt_div_icd)
Similarity
diagnosis_similarity_heatmap(df_gpt3.5, method = "bray")

diagnosis_similarity_heatmap(df_gpt4.0, method = "bray")

diagnosis_similarity_heatmap(df_claude3_haiku_t1.0, method = "bray")

diagnosis_similarity_heatmap(df_claude3_opus_t1.0, method = "bray")

diagnosis_similarity_heatmap(df_gemini1.0_pro_t1.0, method = "bray")

diagnosis_similarity_heatmap(df_gemini1.5_pro_t1.0, method = "bray")

diagnosis_similarity_heatmap(df_gpt3.5_icd, method = "bray")

diagnosis_similarity_heatmap(df_gpt4.0_icd, method = "bray")

diagnosis_similarity_heatmap(df_claude3_haiku_t1.0_icd, method = "bray")

diagnosis_similarity_heatmap(df_claude3_opus_t1.0_icd, method = "bray")

diagnosis_similarity_heatmap(df_gemini1.0_pro_t1.0_icd, method = "bray")

diagnosis_similarity_heatmap(df_gemini1.5_pro_t1.0_icd, method = "bray")

multi_diagnosis_similarity_heatmap(
method = "bray",
show_dend = F,
label_size = 6,
title_size = 9,
df_gpt3.5,
df_gpt4.0,
df_claude3_haiku_t1.0,
df_claude3_opus_t1.0,
df_gemini1.0_pro_t1.0,
df_gemini1.5_pro_t1.0
)

multi_diagnosis_similarity_heatmap(
method = "bray",
show_dend = F,
label_size = 6,
title_size = 9,
df_gpt3.5_icd,
df_gpt4.0_icd,
df_claude3_haiku_t1.0_icd,
df_claude3_opus_t1.0_icd,
df_gemini1.0_pro_t1.0_icd,
df_gemini1.5_pro_t1.0_icd
)

- Bray-Curtis similarity measures the similarity of a given diagnostic
criteria’s set of alternative diagnoses along with their
frequencies.
- This demonstrates that SLE criteria results in a very similar set
and frequency of diagnoses, while the diagnoses associated with two MCAS
criteria are as different from each other as they are from those
generated by the criteria of other conditions.
PCA
diagnosis_pca_plot(df_gpt3.5) + ggtitle("GPT3")

diagnosis_pca_plot(df_gpt4.0) + ggtitle("GPT4")

diagnosis_pca_plot(df_claude3_haiku_t1.0) + ggtitle("Claude Haiku")

diagnosis_pca_plot(df_claude3_opus_t1.0) + ggtitle("Claude Opus")

diagnosis_pca_plot(df_gemini1.0_pro_t1.0) + ggtitle("Gemini")

diagnosis_pca_plot(df_gemini1.5_pro_t1.0) + ggtitle("Gemini")

df <- listN(df_gpt3.5_icd, df_gpt4.0_icd, df_claude3_haiku_t1.0_icd, df_claude3_opus_t1.0_icd, df_gemini1.0_pro_t1.0_icd, df_gemini1.5_pro_t1.0_icd) %>%
mapply(function(x,y) {mutate(x, model=y)}, ., names(.), SIMPLIFY = F) %>%
bind_rows() %>%
count(model, criteria, diagnosis) %>%
pivot_wider(names_from = "diagnosis", values_from = "n", values_fill = 0) %>%
unite(id, model, criteria, sep = "__") %>%
column_to_rownames("id") %>%
prcomp(scale. = F)
as.data.frame(df$x) %>%
rownames_to_column("id") %>%
separate(id, into = c("model", "criteria"), sep = "__") %>%
format_criteria() %>%
format_models() %>%
ggplot(aes(x = PC1, y = PC2, color = criteria))+
geom_point()+
# ggrepel::geom_label_repel() +
theme_bw() +
scale_color_brewer(palette = "Dark2")

Precision
- Precision represents how similar each iteration of a 10-point
differential diagnosis is with all other differential diagnoses from the
same set of criteria.
- I.e. how reproducible the 10-point differential diagnosis is for
each criteria
- Measured by obtaining the Bray-Curtis similarity values between all
iterations within a criteria
# Script for calculating all Bray-Curtis similarity values within a criteria
# Found in source(here("scripts/diversity_analysis/calculate_precision.R"))
# Calculate precision
library(here)
source(here("utils/data_processing.R"))
models <- list.files(here("data/processed_diagnoses"), pattern = "gz$") %>%
str_split("diagnoses_|_icd|.csv") %>%
sapply(., function(x) x[2]) %>%
unique()
use_icd <- TRUE
if (use_icd){models <- str_glue("{models}_icd")}
for (m in models){
print(sprintf("READING IN DATA FOR: %s", m))
read_path <- sprintf("data/processed_diagnoses/diagnoses_%s.csv.gz", m)
df <- read_csv(here(read_path))
print(sprintf("CALCULATING PRECISION FOR: %s", m))
df <- calculate_precision(df)
print(sprintf("WRITING PRECISION DATA FOR: %s", m))
out_path <- sprintf("data/diversity_analysis/diagnosis_precision_%s.csv.gz", m)
write_csv(df, here(out_path))
}
precision_dist_to_sim <- function(df){
df %>%
mutate(
mean = 1-mean,
max = 1-min,
min = 1-max
)
}
plt_precision_icd <- read_csv(here("data/diversity_analysis/compiled_icd_diagnosis_precision.csv")) %>%
precision_dist_to_sim() %>%
format_criteria() %>%
format_models() %>%
filter(model != "Gemini 1.5 Flash") %>%
ggplot(aes(x = criteria, y = mean))+
theme_bw()+
theme(axis.text.x = element_text(angle= 45, hjust = 1))+
labs(x="", y = "Average Bray-Curtis Similarity") +
ggpubr::geom_pwc(aes(group = criteria), method = "wilcox.test", p.adjust.method = "BH", hide.ns = T, label = "p.adj.signif", bracket.nudge.y = 0.3, vjust = 0.6, step.increase = 0.14, tip.length = 0.02) +
labs(color=NULL)+
scale_color_brewer(palette = "Dark2") +
plot_selector("points")
Rows: 42 Columns: 8── Column specification ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (2): criteria, model
dbl (6): n, mean, max, min, sd, se
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.Scale for colour is already present.
Adding another scale for colour, which will replace the existing scale.
plt_precision_icd

plt_precision_icd$data %>% summarise(mean = mean(mean), .by="criteria")
extract_ggpubr_pvalues(plt_precision_icd)
iNEXT
inext_plots <- function(inext_obj){
for (i in 1:3){
plt <- iNEXT::ggiNEXT(inext_obj, type=i, facet.var="Assemblage", color.var="Assemblage") +
theme_classic() +
scale_color_brewer(palette = "Set1") +
theme(axis.text.x = element_text(angle = 90))+
scale_color_brewer(palette = "Dark2")
print(plt)
}
}
readRDS(here("data/diversity_analysis/mcas_iNEXT_gpt4_e250000.RDS")) %>% inext_plots()
Scale for colour is already present.
Adding another scale for colour, which will replace the existing scale.Scale for colour is already present.
Adding another scale for colour, which will replace the existing scale.



readRDS(here("data/diversity_analysis/mcas_iNEXT_dropSingle_gpt4_e200000.RDS")) %>% inext_plots()
Scale for colour is already present.
Adding another scale for colour, which will replace the existing scale.Scale for colour is already present.
Adding another scale for colour, which will replace the existing scale.



readRDS(here("data/diversity_analysis/mcas_iNEXT_dropSingle_psuedoMinus_gpt4_e200000.RDS")) %>% inext_plots()
Scale for colour is already present.
Adding another scale for colour, which will replace the existing scale.Scale for colour is already present.
Adding another scale for colour, which will replace the existing scale.



# custom_labeler <- function(x, wrap_width=33) {
# x %>%
# str_replace("___.+$", "") %>%
# str_wrap(width = wrap_width)
# }
Final plot
Version 1
n_diagnoses_bar <- 10
n_diagnoses_abundance <- 50
n_diagnoses_cumulative <- 50
title_size <- 9
label_size <- 6
legend_x_pad <- 4
legend_y_pad <- 2
apply_text_formatting <- list(theme(
axis.text = element_text(size = label_size),
axis.title = element_text(size = title_size),
legend.text = element_text(size = label_size),
strip.text = element_text(size = label_size+1),
legend.key.height = unit(0.4, 'cm'),
legend.box.background = element_rect(color = "black", size = 1),
legend.margin = margin(t = legend_y_pad, r = legend_x_pad, b = legend_y_pad, l = legend_x_pad*1.1),
legend.spacing.x = unit(0, 'cm'), # Horizontal spacing between legend items
# legend.spacing.y = unit(0, 'cm'),
# legend.box.spacing = unit(0, "cm")
))
strip_margin <- 1
strip_formatting <- list(theme(
strip.text.x = element_text(margin = margin(t = strip_margin, r = strip_margin, b = strip_margin, l = strip_margin)),
strip.text.y = element_text(margin = margin(t = strip_margin, r = strip_margin, b = strip_margin, l = strip_margin))
# strip.background = element_rect(margin = margin(t = strip_margin, r = strip_margin, b = strip_margin, l = strip_margin))
))
plt_diags <-
multi_top_diagnosis_plot(
distribution_vis = "points",
wrap_width = 58,
n_diag = n_diagnoses_bar,
df_gpt3.5_icd,
df_gpt4.0_icd,
df_claude3_haiku_t1.0_icd,
df_claude3_opus_t1.0_icd,
df_gemini1.0_pro_t1.0_icd,
df_gemini1.5_flash_t1.0_icd
) +
theme(legend.position = "bottom", legend.direction = "horizontal") +
apply_text_formatting +
theme(axis.text.y = element_text(size = 6.5)) +
strip_formatting +
# theme(legend.position = c(-1,0))+
theme(panel.spacing = unit(0, "lines")) +
guides(color = guide_legend(override.aes = list(size = 2))) # Increase the point size in the legend)
plt_rank <-
multi_ranked_abundance_plot(
df_gpt3.5_icd,
df_gpt4.0_icd,
df_claude3_haiku_t1.0_icd,
df_claude3_opus_t1.0_icd,
df_gemini1.0_pro_t1.0_icd,
df_gemini1.5_pro_t1.0_icd
) +
theme(legend.position = "bottom", legend.direction = "horizontal") +
apply_text_formatting +
guides(color = guide_legend(ncol = 2))
plt_cumulative <- multi_cumulative_frequency_plot(
n_diagnoses = n_diagnoses_cumulative,
distribution_vis = "points",
df_gpt3.5_icd,
df_gpt4.0_icd,
df_claude3_haiku_t1.0_icd,
df_claude3_opus_t1.0_icd,
df_gemini1.0_pro_t1.0_icd
) +
theme(legend.position = "bottom", legend.direction = "horizontal") +
apply_text_formatting +
guides(color = guide_legend(ncol = 2)) +
labs(y = "Combined frequency\nof top 50 diagnoses", x = NULL)
plt_shannon <- multi_shannon_plot(
distribution_vis = "points",
wrap_width = 45,
n_diag = 25,
df_gpt3.5_icd,
df_gpt4.0_icd,
df_claude3_haiku_t1.0_icd,
df_claude3_opus_t1.0_icd,
df_gemini1.0_pro_t1.0_icd,
df_gemini1.5_pro_t1.0_icd
) +
apply_text_formatting +
theme(legend.position = "bottom", legend.direction = "horizontal") +
guides(color = guide_legend(ncol = 2))
plt_precision <- read_csv(here("data/diversity_analysis/compiled_icd_diagnosis_precision.csv")) %>%
precision_dist_to_sim() %>%
format_criteria() %>%
format_models() %>%
filter(model != "Gemini 1.5 Flash") %>%
ggplot(aes(x = criteria, y = mean))+
theme_bw()+
theme(axis.text.x = element_text(angle= 45, hjust = 1))+
labs(x="", y = "Average Bray-Curtis\nSimilarity") +
ggpubr::geom_pwc(aes(group = criteria), method = "wilcox.test", p.adjust.method = "BH", hide.ns = T, label = "p.adj.signif", bracket.nudge.y = 0.3, vjust = 0.6, step.increase = 0.14, tip.length = 0.02) +
labs(color=NULL)+
scale_color_brewer(palette = "Dark2") +
plot_selector("points") +
apply_text_formatting +
theme(legend.position = "bottom", legend.direction = "horizontal") +
guides(color = guide_legend(ncol = 2))
full_plt <- plot_grid(
###
plt_diags,
###
NULL,
plot_grid(
plt_rank,
plt_cumulative,
plt_shannon,
plt_precision,
nrow = 1,
axis = 'tb',
align = 'h',
rel_widths = c(1, 0.7, 0.7, 0.7),
labels = c(LETTERS[2:5]),
vjust = 0.2
),
ncol = 1,
rel_heights = c(1.2, 0.05, 0.65),
labels = c("A","","")
)
full_plt

Version 2
n_diagnoses_bar <- 10
n_diagnoses_abundance <- 50
n_diagnoses_cumulative <- 50
title_size <- 9
label_size <- 6
legend_x_pad <- 4
legend_y_pad <- 2
apply_text_formatting <- list(theme(
axis.text = element_text(size = label_size),
axis.title = element_text(size = title_size),
legend.text = element_text(size = label_size),
strip.text = element_text(size = label_size+1),
legend.key.height = unit(0.4, 'cm'),
legend.box.background = element_rect(color = "black", size = 1),
legend.margin = margin(t = legend_y_pad, r = legend_x_pad, b = legend_y_pad, l = legend_x_pad*1.1),
legend.spacing.x = unit(0, 'cm'), # Horizontal spacing between legend items
# legend.spacing.y = unit(0, 'cm'),
# legend.box.spacing = unit(0, "cm")
))
strip_margin <- 1
strip_formatting <- list(theme(
strip.text.x = element_text(margin = margin(t = strip_margin, r = strip_margin, b = strip_margin, l = strip_margin)),
strip.text.y = element_text(margin = margin(t = strip_margin, r = strip_margin, b = strip_margin, l = strip_margin))
# strip.background = element_rect(margin = margin(t = strip_margin, r = strip_margin, b = strip_margin, l = strip_margin))
))
plt_diags <-
multi_top_diagnosis_plot(
distribution_vis = "points",
wrap_width = 58,
n_diag = n_diagnoses_bar,
df_gpt3.5_icd,
df_gpt4.0_icd,
df_claude3_haiku_t1.0_icd,
df_claude3_opus_t1.0_icd,
df_gemini1.0_pro_t1.0_icd,
df_gemini1.5_flash_t1.0_icd
) +
theme(legend.position = "bottom", legend.direction = "horizontal") +
apply_text_formatting +
theme(axis.text.y = element_text(size = 6.5)) +
strip_formatting +
# theme(legend.position = c(-1,0))+
theme(panel.spacing = unit(0, "lines")) +
guides(color = guide_legend(override.aes = list(size = 2), nrow = 1)) # Increase the point size in the legend)
plt_rank <-
multi_ranked_abundance_plot(
df_gpt3.5_icd,
df_gpt4.0_icd,
df_claude3_haiku_t1.0_icd,
df_claude3_opus_t1.0_icd,
df_gemini1.0_pro_t1.0_icd,
df_gemini1.5_pro_t1.0_icd
) +
theme(legend.position = c(0.7,0.7))+
# theme(legend.position = "bottom", legend.direction = "horizontal") +
apply_text_formatting +
guides(color = guide_legend(ncol = 1)) +
labs(color = NULL)
plt_cumulative <- multi_cumulative_frequency_plot(
n_diagnoses = n_diagnoses_cumulative,
distribution_vis = "points",
df_gpt3.5_icd,
df_gpt4.0_icd,
df_claude3_haiku_t1.0_icd,
df_claude3_opus_t1.0_icd,
df_gemini1.0_pro_t1.0_icd
) +
theme(legend.position = "bottom", legend.direction = "horizontal") +
apply_text_formatting +
guides(color = guide_legend(ncol = 2)) +
labs(y = "Combined frequency\nof top 50 diagnoses", x = NULL)
plt_shannon <- multi_shannon_plot(
distribution_vis = "points",
wrap_width = 45,
n_diag = 25,
df_gpt3.5_icd,
df_gpt4.0_icd,
df_claude3_haiku_t1.0_icd,
df_claude3_opus_t1.0_icd,
df_gemini1.0_pro_t1.0_icd,
df_gemini1.5_pro_t1.0_icd
) +
apply_text_formatting +
theme(legend.position = "bottom", legend.direction = "horizontal") +
guides(color = guide_legend(ncol = 2))
plt_precision <- read_csv(here("data/diversity_analysis/compiled_icd_diagnosis_precision.csv")) %>%
precision_dist_to_sim() %>%
format_criteria() %>%
format_models() %>%
filter(model != "Gemini 1.5 Flash") %>%
ggplot(aes(x = criteria, y = mean))+
theme_bw()+
theme(axis.text.x = element_text(angle= 45, hjust = 1))+
labs(x="", y = "Average Bray-Curtis\nSimilarity") +
ggpubr::geom_pwc(aes(group = criteria), method = "wilcox.test", p.adjust.method = "BH", hide.ns = T, label = "p.adj.signif", bracket.nudge.y = 0.3, vjust = 0.6, step.increase = 0.14, tip.length = 0.02) +
labs(color=NULL)+
scale_color_brewer(palette = "Dark2") +
plot_selector("points") +
apply_text_formatting +
theme(legend.position = "bottom", legend.direction = "horizontal") +
guides(color = guide_legend(ncol = 2))
full_plt <- plot_grid(
###
plt_diags,
###
NULL,
plot_grid(
plt_rank,
plot_grid(
plot_grid(
plt_shannon+ theme(legend.position="none"),
plt_precision+ theme(legend.position="none"),
nrow = 1,
axis = 'tb',
align = 'h'
),
get_legend(plt_shannon+ guides(color = guide_legend(row = 1))),
ncol = 1,
rel_heights = c(1,0.1)
),
nrow = 1,
rel_widths = c(1,1),
# labels = c(LETTERS[2:5]),
vjust = 0.2
),
ncol = 1,
rel_heights = c(1.2, 0.05, 0.65),
labels = c("A","","")
)
full_plt

Version 3
n_diagnoses_bar <- 10
n_diagnoses_abundance <- 50
n_diagnoses_cumulative <- 50
title_size <- 9
label_size <- 6
legend_x_pad <- 4
legend_y_pad <- 2
apply_text_formatting <- list(theme(
axis.text = element_text(size = label_size),
axis.title = element_text(size = title_size),
legend.text = element_text(size = label_size),
strip.text = element_text(size = label_size+1),
legend.key.height = unit(0.4, 'cm'),
legend.box.background = element_rect(color = "black", size = 1),
legend.margin = margin(t = legend_y_pad, r = legend_x_pad, b = legend_y_pad, l = legend_x_pad*1.1),
legend.spacing.x = unit(0, 'cm'), # Horizontal spacing between legend items
# legend.spacing.y = unit(0, 'cm'),
# legend.box.spacing = unit(0, "cm")
))
strip_margin <- 1
strip_formatting <- list(theme(
strip.text.x = element_text(margin = margin(t = strip_margin, r = strip_margin, b = strip_margin, l = strip_margin)),
strip.text.y = element_text(margin = margin(t = strip_margin, r = strip_margin, b = strip_margin, l = strip_margin))
# strip.background = element_rect(margin = margin(t = strip_margin, r = strip_margin, b = strip_margin, l = strip_margin))
))
plt_diags <-
multi_top_diagnosis_plot(
distribution_vis = "points",
wrap_width = 58,
n_diag = n_diagnoses_bar,
df_gpt3.5_icd,
df_gpt4.0_icd,
df_claude3_haiku_t1.0_icd,
df_claude3_opus_t1.0_icd,
df_gemini1.0_pro_t1.0_icd,
df_gemini1.5_flash_t1.0_icd
) +
theme(legend.position = "bottom", legend.direction = "horizontal") +
apply_text_formatting +
theme(axis.text.y = element_text(size = 6.5)) +
strip_formatting +
# theme(legend.position = c(-1,0))+
theme(panel.spacing = unit(0, "lines")) +
guides(color = guide_legend(override.aes = list(size = 2), nrow = 1)) # Increase the point size in the legend)
plt_rank <-
multi_ranked_abundance_plot(
df_gpt3.5_icd,
df_gpt4.0_icd,
df_claude3_haiku_t1.0_icd,
df_claude3_opus_t1.0_icd,
df_gemini1.0_pro_t1.0_icd,
df_gemini1.5_pro_t1.0_icd
) +
theme(legend.position = c(0.7,0.7))+
# theme(legend.position = "bottom", legend.direction = "horizontal") +
apply_text_formatting +
guides(color = guide_legend(ncol = 1)) +
labs(color = NULL)
plt_cumulative <- multi_cumulative_frequency_plot(
n_diagnoses = n_diagnoses_cumulative,
distribution_vis = "points",
df_gpt3.5_icd,
df_gpt4.0_icd,
df_claude3_haiku_t1.0_icd,
df_claude3_opus_t1.0_icd,
df_gemini1.0_pro_t1.0_icd
) +
theme(legend.position = "bottom", legend.direction = "horizontal") +
apply_text_formatting +
guides(color = guide_legend(ncol = 2)) +
labs(y = "Combined frequency\nof top 50 diagnoses", x = NULL)
plt_shannon <- multi_shannon_plot(
distribution_vis = "points",
wrap_width = 45,
n_diag = 25,
df_gpt3.5_icd,
df_gpt4.0_icd,
df_claude3_haiku_t1.0_icd,
df_claude3_opus_t1.0_icd,
df_gemini1.0_pro_t1.0_icd,
df_gemini1.5_pro_t1.0_icd
) +
apply_text_formatting +
theme(legend.position = "bottom", legend.direction = "horizontal") +
guides(color = guide_legend(ncol = 2))
plt_precision <- read_csv(here("data/diversity_analysis/compiled_icd_diagnosis_precision.csv")) %>%
precision_dist_to_sim() %>%
format_criteria() %>%
format_models() %>%
filter(model != "Gemini 1.5 Flash") %>%
ggplot(aes(x = criteria, y = mean))+
theme_bw()+
theme(axis.text.x = element_text(angle= 45, hjust = 1))+
labs(x="", y = "Mean Bray-Curtis Similarity") +
ggpubr::geom_pwc(aes(group = criteria), method = "wilcox.test", p.adjust.method = "BH", hide.ns = T, label = "p.adj.signif", bracket.nudge.y = 0.3, vjust = 0.6, step.increase = 0.14, tip.length = 0.02) +
labs(color=NULL)+
scale_color_brewer(palette = "Dark2") +
plot_selector("points") +
apply_text_formatting +
theme(legend.position = "bottom", legend.direction = "horizontal") +
guides(color = guide_legend(ncol = 2))
plt_similarity <- multi_diagnosis_similarity_heatmap(
method = "bray",
show_dend = F,
legend_label = "Bray-Curtis similarity",
legend_direction = "horizontal",
label_size = 6,
title_size = 9,
df_gpt3.5_icd,
df_gpt4.0_icd,
df_claude3_haiku_t1.0_icd,
df_claude3_opus_t1.0_icd,
df_gemini1.0_pro_t1.0_icd,
df_gemini1.5_pro_t1.0_icd
)
full_plt <- plot_grid(
###
plt_diags,
###
NULL,
plot_grid(
grid::grid.grabExpr(ComplexHeatmap::draw(plt_similarity, heatmap_legend_side = 'bottom')),
plt_rank,
# NULL,
plot_grid(
plot_grid(
plt_shannon+ theme(legend.position="none"),
plt_precision+ theme(legend.position="none"),
nrow = 1,
axis = 'tb',
align = 'h',
labels = c(LETTERS[4:5])
),
get_legend(plt_shannon+ guides(color = guide_legend(row = 1))),
ncol = 1,
rel_heights = c(1,0.1)
),
nrow = 1,
# rel_widths = c(1, 0.01, 0.8, 0.9),
rel_widths = c(0.8, 1,0.9),
labels = c(LETTERS[2:3]),
vjust = 0.2
),
ncol = 1,
rel_heights = c(1.2, 0.05, 0.65),
labels = c("A","","")
)
full_plt

Things to fix - Legend position for C-E - Legend width for B - Move
legend for A to the left of “Frequency?” - Rank plot line weight
ggsave(plot=full_plt,filename=here("figures/3_diagnosis_diversity.pdf"), width = 7.5, height = 7.5)
set_table_properties(opts_pdf = list(tabcolsep = 0))
set_flextable_defaults(fonts_ignore=TRUE)
multi_diagnosis_rank_table(search_pattern = "T78\\.2 |D47\\.02 |D89\\.41 |D89\\.49 |D89\\.4 ",
df_gpt3.5_icd, df_gpt4.0_icd, df_claude3_haiku_t1.0_icd, df_claude3_opus_t1.0_icd, df_gemini1.0_pro_t1.0_icd) %>%
flextable() %>%
width(width = 2) %>%
fontsize(size = 9) %>%
fontsize(size = 10, part = "header") %>%
padding(padding = 0) %>%
align(j = 2:3, align = "center", part = "all") %>%
set_table_properties(opts_pdf = list(arraystretch = 1.25)) %>%
{print(., preview = "pdf");.}
LS0tCnRpdGxlOiAiRGlhZ25vc2lzIGRpc3RyaWJ1dGlvbiBhbmFseXNpcyIKb3V0cHV0OiAKICBodG1sX25vdGVib29rOgogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKLS0tCgpgYGB7ciwgbWVzc2FnZSA9IEZ9CmxpYnJhcnkoaGVyZSkKbGlicmFyeShjb3dwbG90KQpzb3VyY2UoaGVyZSgidXRpbHMvZGF0YV9wcm9jZXNzaW5nLlIiKSkKc291cmNlKGhlcmUoInV0aWxzL2ZpZ3VyZXMuUiIpKQpgYGAKCmBgYHtyfQphbGxfbW9kZWxzIDwtIGxpc3QuZmlsZXMoaGVyZSgiZGF0YS9wcm9jZXNzZWRfZGlhZ25vc2VzIiksIHBhdHRlcm4gPSAiZ3okIikgJT4lIAogIHN0cl9zcGxpdCgiZGlhZ25vc2VzX3xfaWNkfC5jc3YiKSAlPiUgCiAgc2FwcGx5KC4sIGZ1bmN0aW9uKHgpIHhbMl0pICU+JSAKICB1bmlxdWUoKQphbGxfbW9kZWxzCmBgYAojIEltcG9ydCBkYXRhCgpgYGB7ciwgbWVzc2FnZSA9IEZ9CmRmX2dwdDMuNSA8LSByZWFkX21vZGVsKCJncHQtMy41LXR1cmJvLTExMDYiLCBpY2QgPSBGQUxTRSkKZGZfZ3B0NC4wIDwtIHJlYWRfbW9kZWwoImdwdC00LXR1cmJvLXByZXZpZXciLCBpY2QgPSBGQUxTRSkKZGZfY2xhdWRlM19oYWlrdV90MS4wIDwtIHJlYWRfbW9kZWwoImNsYXVkZS0zLWhhaWt1LTIwMjQwMzA3X3QxLTAiLCBpY2QgPSBGQUxTRSkKZGZfY2xhdWRlM19vcHVzX3QxLjAgPC0gcmVhZF9tb2RlbCgiY2xhdWRlLTMtb3B1cy0yMDI0MDIyOV90MS0wIiwgaWNkID0gRkFMU0UpCmRmX2dlbWluaTEuMF9wcm9fdDEuMCA8LSByZWFkX21vZGVsKCJnZW1pbmktMS4wLXByby0wMDJfdDEtMCIsIGljZCA9IEZBTFNFKQpkZl9nZW1pbmkxLjVfcHJvX3QxLjAgPC0gcmVhZF9tb2RlbCgiZ2VtaW5pLTEuNS1wcm8tMDAxX3QxLTAiLCBpY2QgPSBGQUxTRSkKYGBgCgpgYGB7ciwgbWVzc2FnZSA9IEZ9CmRmX2dwdDMuNV9pY2QgPC0gcmVhZF9tb2RlbCgiZ3B0LTMuNS10dXJiby0xMTA2IiwgaWNkID0gVFJVRSkKZGZfZ3B0NC4wX2ljZCA8LSByZWFkX21vZGVsKCJncHQtNC10dXJiby1wcmV2aWV3IiwgaWNkID0gVFJVRSkKZGZfY2xhdWRlM19oYWlrdV90MS4wX2ljZCA8LSByZWFkX21vZGVsKCJjbGF1ZGUtMy1oYWlrdS0yMDI0MDMwN190MS0wIiwgaWNkID0gVFJVRSkKZGZfY2xhdWRlM19vcHVzX3QxLjBfaWNkIDwtIHJlYWRfbW9kZWwoImNsYXVkZS0zLW9wdXMtMjAyNDAyMjlfdDEtMCIsIGljZCA9IFRSVUUpCmRmX2dlbWluaTEuMF9wcm9fdDEuMF9pY2QgPC0gcmVhZF9tb2RlbCgiZ2VtaW5pLTEuMC1wcm8tMDAyX3QxLTAiLCBpY2QgPSBUUlVFKQpkZl9nZW1pbmkxLjVfcHJvX3QxLjBfaWNkIDwtIHJlYWRfbW9kZWwoImdlbWluaS0xLjUtcHJvLTAwMV90MS0wIiwgaWNkID0gVFJVRSkKYGBgCgoKIyBSYW5rIGFidW5kYW5jZQoKKipPcmlnaW5hbCByZXNwb25zZXMqKgpgYGB7cn0KcmFua19hYnVuZGFuY2VfcGxvdChkZl9ncHQzLjUpK2dndGl0bGUoIkNoYXRHUFQgMy41IikKcmFua19hYnVuZGFuY2VfcGxvdChkZl9ncHQ0LjApK2dndGl0bGUoIkNoYXRHUFQgNC4wIikKcmFua19hYnVuZGFuY2VfcGxvdChkZl9jbGF1ZGUzX2hhaWt1X3QxLjApK2dndGl0bGUoIkNsYXVkZTMgSGFpa3UgdDEuMCIpCnJhbmtfYWJ1bmRhbmNlX3Bsb3QoZGZfY2xhdWRlM19vcHVzX3QxLjApK2dndGl0bGUoIkNsYXVkZTMgT3B1cyIpCnJhbmtfYWJ1bmRhbmNlX3Bsb3QoZGZfZ2VtaW5pMS4wX3Byb190MS4wKStnZ3RpdGxlKCJHZW1pbmkgMS4wIFBybyIpCnJhbmtfYWJ1bmRhbmNlX3Bsb3QoZGZfZ2VtaW5pMS41X3Byb190MS4wKStnZ3RpdGxlKCJHZW1pbmkgMS41IFBybyIpCmBgYAoKKipJQ0QgY29udmVydGVkIHJlc3BvbnNlcyoqCmBgYHtyfQpyYW5rX2FidW5kYW5jZV9wbG90KGRmX2dwdDMuNV9pY2QpK2dndGl0bGUoIkNoYXRHUFQgMy41IElDRCIpCnJhbmtfYWJ1bmRhbmNlX3Bsb3QoZGZfZ3B0NC4wX2ljZCkrZ2d0aXRsZSgiQ2hhdEdQVCA0LjAgSUNEIikKcmFua19hYnVuZGFuY2VfcGxvdChkZl9jbGF1ZGUzX2hhaWt1X3QxLjBfaWNkKStnZ3RpdGxlKCJDbGF1ZGUzIEhhaWt1IElDRCIpCnJhbmtfYWJ1bmRhbmNlX3Bsb3QoZGZfY2xhdWRlM19vcHVzX3QxLjBfaWNkKStnZ3RpdGxlKCJDbGF1ZGUzIE9wdXMgSUNEIikKcmFua19hYnVuZGFuY2VfcGxvdChkZl9nZW1pbmkxLjBfcHJvX3QxLjBfaWNkKStnZ3RpdGxlKCJHZW1pbmkgMS4wIFBybyBJQ0QiKQpyYW5rX2FidW5kYW5jZV9wbG90KGRmX2dlbWluaTEuNV9wcm9fdDEuMF9pY2QpK2dndGl0bGUoIkdlbWluaSAxLjUgUHJvIElDRCIpCmBgYAoKKipDb21iaW5lZCBtb2RlbCBkYXRhKioKCmBgYHtyfQptdWx0aV9yYW5rZWRfYWJ1bmRhbmNlX3Bsb3QoZGZfZ3B0My41LCBkZl9ncHQ0LjAsIGRmX2NsYXVkZTNfaGFpa3VfdDEuMCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZl9jbGF1ZGUzX29wdXNfdDEuMCwgZGZfZ2VtaW5pMS4wX3Byb190MS4wLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgZGZfZ2VtaW5pMS41X3Byb190MS4wKSsKICBnZ3RpdGxlKCJDb21iaW5lZCBtb2RlbCByYW5rIGFidW5kYW5jZSIsICJPcmlnaW5hbCByZXNwb25zZXMiKQpgYGAKCmBgYHtyfQptdWx0aV9yYW5rZWRfYWJ1bmRhbmNlX3Bsb3QoZGZfZ3B0My41X2ljZCwgZGZfZ3B0NC4wX2ljZCwgZGZfY2xhdWRlM19oYWlrdV90MS4wX2ljZCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZl9jbGF1ZGUzX29wdXNfdDEuMF9pY2QsIGRmX2dlbWluaTEuMF9wcm9fdDEuMF9pY2QsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgZGZfZ2VtaW5pMS41X3Byb190MS4wX2ljZCkrCiAgZ2d0aXRsZSgiQ29tYmluZWQgbW9kZWwgcmFuayBhYnVuZGFuY2UiLCAiSUNEIGNvbnZlcnRlZCByZXNwb25zZXMiKQpgYGAKCiMgVG9wIGRpYWdub3NlcyBwbG90cwoKYGBge3IsIGZpZy53aWR0aCA9IDEyLCBmaWcuaGVpZ2h0ID0gOH0KY3VzdG9tX2xhYmVsZXIgPC0gZnVuY3Rpb24oeCwgd3JhcF93aWR0aD0zMykgewogICAgeCAlPiUKICAgICAgICBzdHJfcmVwbGFjZSgiX19fLiskIiwgIiIpICU+JQogICAgICAgIHN0cl93cmFwKHdpZHRoID0gd3JhcF93aWR0aCkKfQoKY3VzdG9tX3RleHRfZm9ybWF0dGluZyA8LSBsaXN0KAogIHRoZW1lKGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gNywgbGluZWhlaWdodCA9IDAuNyksIAogICAgICAgICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gNyksCiAgICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA5KSksCiAgdGlkeXRleHQ6OnNjYWxlX3hfcmVvcmRlcmVkKGxhYmVscyA9IH5jdXN0b21fbGFiZWxlciguLCB3cmFwX3dpZHRoID0gNDUpKQopCmBgYAoKYGBge3IsIGZpZy53aWR0aCA9IDE2LCBmaWcuaGVpZ2h0ID0gOH0Kbl9kaWFnIDwtIDI1CnN1YiA8LSAiT3JpZ2luYWwgcmVzcG9uc2VzIgp0b3BfZGlhZ25vc2lzX3Bsb3QoZGZfZ3B0My41LCBuX2RpYWcgPSBuX2RpYWcpK2dndGl0bGUoIkNoYXRHUFQgMy41Iiwgc3ViKQp0b3BfZGlhZ25vc2lzX3Bsb3QoZGZfZ3B0NC4wLCBuX2RpYWcgPSBuX2RpYWcpK2dndGl0bGUoIkNoYXRHUFQgNC4wIiwgc3ViKQp0b3BfZGlhZ25vc2lzX3Bsb3QoZGZfY2xhdWRlM19oYWlrdV90MS4wLCBuX2RpYWcgPSBuX2RpYWcpK2dndGl0bGUoIkNsYXVkZTMgSGFpa3UgdDEuMCIsIHN1YikKdG9wX2RpYWdub3Npc19wbG90KGRmX2NsYXVkZTNfb3B1c190MS4wLCBuX2RpYWcgPSBuX2RpYWcpK2dndGl0bGUoIkNsYXVkZTMgT3B1cyB0MS4wIiwgc3ViKQp0b3BfZGlhZ25vc2lzX3Bsb3QoZGZfZ2VtaW5pMS4wX3Byb190MS4wLCBuX2RpYWcgPSBuX2RpYWcpK2dndGl0bGUoIkdlbWluaSAxLjAgUHJvIiwgc3ViKQp0b3BfZGlhZ25vc2lzX3Bsb3QoZGZfZ2VtaW5pMS41X3Byb190MS4wLCBuX2RpYWcgPSBuX2RpYWcpK2dndGl0bGUoIkdlbWluaSAxLjUgUHJvIiwgc3ViKQpgYGAKCmBgYHtyLCBmaWcud2lkdGggPSAxNiwgZmlnLmhlaWdodCA9IDEwfQpuX2RpYWcgPC0gMjUKc3ViIDwtICJJQ0QgY29udmVydGVkIHJlc3BvbnNlcyIKdG9wX2RpYWdub3Npc19wbG90KGRmX2dwdDMuNV9pY2QsIG5fZGlhZyA9IG5fZGlhZykgKyBjdXN0b21fdGV4dF9mb3JtYXR0aW5nICsgZ2d0aXRsZSgiQ2hhdEdQVCAzLjUgSUNEIiwgc3ViKSAKdG9wX2RpYWdub3Npc19wbG90KGRmX2dwdDQuMF9pY2QsIG5fZGlhZyA9IG5fZGlhZykrIGN1c3RvbV90ZXh0X2Zvcm1hdHRpbmcrZ2d0aXRsZSgiQ2hhdEdQVCA0LjAgSUNEIiwgc3ViKQp0b3BfZGlhZ25vc2lzX3Bsb3QoZGZfY2xhdWRlM19oYWlrdV90MS4wX2ljZCwgbl9kaWFnID0gbl9kaWFnKSsgY3VzdG9tX3RleHRfZm9ybWF0dGluZytnZ3RpdGxlKCJDbGF1ZGUzIEhhaWt1IHQxLjAgSUNEIiwgc3ViKQp0b3BfZGlhZ25vc2lzX3Bsb3QoZGZfY2xhdWRlM19vcHVzX3QxLjBfaWNkLCBuX2RpYWcgPSBuX2RpYWcpKyBjdXN0b21fdGV4dF9mb3JtYXR0aW5nK2dndGl0bGUoIkNsYXVkZTMgT3B1cyB0MS4wIElDRCIsIHN1YikKdG9wX2RpYWdub3Npc19wbG90KGRmX2dlbWluaTEuMF9wcm9fdDEuMF9pY2QsIG5fZGlhZyA9IG5fZGlhZykrIGN1c3RvbV90ZXh0X2Zvcm1hdHRpbmcrZ2d0aXRsZSgiR2VtaW5pIDEuMCBQcm8gSUNEIiwgc3ViKQp0b3BfZGlhZ25vc2lzX3Bsb3QoZGZfZ2VtaW5pMS41X3Byb190MS4wX2ljZCwgbl9kaWFnID0gbl9kaWFnKSsgY3VzdG9tX3RleHRfZm9ybWF0dGluZytnZ3RpdGxlKCJHZW1pbmkgMS41IFBybyBJQ0QiLCBzdWIpCmBgYAoKYGBge3IsIGZpZy53aWR0aCA9IDE2LCBmaWcuaGVpZ2h0ID0gMTB9Cm11bHRpX3RvcF9kaWFnbm9zaXNfcGxvdChkaXN0cmlidXRpb25fdmlzID0gInBvaW50cyIsIHdyYXBfd2lkdGg9NDUsIG5fZGlhZyA9IDI1LAogICAgICAgICAgICAgICAgICAgICAgICAgZGZfZ3B0My41LCBkZl9ncHQ0LjAsIGRmX2NsYXVkZTNfaGFpa3VfdDEuMCwgCiAgICAgICAgICAgICAgICAgICAgICAgICBkZl9jbGF1ZGUzX29wdXNfdDEuMCwgZGZfZ2VtaW5pMS4wX3Byb190MS4wLAogICAgICAgICAgICAgICAgICAgICAgICAgZGZfZ2VtaW5pMS41X3Byb190MS4wKQpgYGAKCgoKYGBge3IsIGZpZy53aWR0aCA9IDE2LCBmaWcuaGVpZ2h0ID0gMTB9CnBsdF9kaWFnX2ljZCA8LSBtdWx0aV90b3BfZGlhZ25vc2lzX3Bsb3QoZGlzdHJpYnV0aW9uX3ZpcyA9ICJwb2ludHMiLCB3cmFwX3dpZHRoID0gMzMsIG5fZGlhZyA9IDE1LAogICAgICAgICAgICAgICAgICAgICAgICAgZGZfZ3B0My41X2ljZCwgZGZfZ3B0NC4wX2ljZCwgZGZfY2xhdWRlM19oYWlrdV90MS4wX2ljZCwgCiAgICAgICAgICAgICAgICAgICAgICAgICBkZl9jbGF1ZGUzX29wdXNfdDEuMF9pY2QsIGRmX2dlbWluaTEuMF9wcm9fdDEuMF9pY2QsIAogICAgICAgICAgICAgICAgICAgICAgICAgZGZfZ2VtaW5pMS41X3Byb190MS4wX2ljZCkgKwogIGd1aWRlcyhzaXplID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZSA9IDIpKSkKCnBsdF9kaWFnX2ljZApwbHRfZGlhZ19pY2QkZGF0YSAlPiUgCiAgc3VtbWFyaXNlKGZyZXE9bWVhbihmcmVxKSwuYnk9YygiY3JpdGVyaWEiLCJkaWFnbm9zaXMiKSkgJT4lIAogIGFycmFuZ2UoY3JpdGVyaWEsIGRlc2MoZnJlcSkpCmBgYAoKIyBDdW11bGF0aXZlIHRvcCBmcmVxdWVuY3kgcGxvdHMKCgpgYGB7ciwgZmlnLndpZHRoPTMsIGZpZy5oZWlnaHQ9My41fQpzdWIgPC0gIk9yaWdpbmFsIHJlc3BvbnNlcyIKY3VtdWxhdGl2ZV9mcmVxdWVuY3lfcGxvdChkZl9ncHQzLjUpJHBsb3QrZ2d0aXRsZSgiR1BUMyIsIHN1YikKY3VtdWxhdGl2ZV9mcmVxdWVuY3lfcGxvdChkZl9ncHQ0LjApJHBsb3QrZ2d0aXRsZSgiR1BUNCIsIHN1YikKY3VtdWxhdGl2ZV9mcmVxdWVuY3lfcGxvdChkZl9jbGF1ZGUzX2hhaWt1X3QxLjApJHBsb3QrZ2d0aXRsZSgiQ2xhdWRlMyBIYWlrdSIsIHN1YikKY3VtdWxhdGl2ZV9mcmVxdWVuY3lfcGxvdChkZl9jbGF1ZGUzX29wdXNfdDEuMCkkcGxvdCtnZ3RpdGxlKCJDbGF1ZGUzIEhhaWt1Iiwgc3ViKQpjdW11bGF0aXZlX2ZyZXF1ZW5jeV9wbG90KGRmX2dlbWluaTEuMF9wcm9fdDEuMCkkcGxvdCtnZ3RpdGxlKCJHZW1pbmkgUHJvIDEuMCIsIHN1YikKY3VtdWxhdGl2ZV9mcmVxdWVuY3lfcGxvdChkZl9nZW1pbmkxLjVfcHJvX3QxLjApJHBsb3QrZ2d0aXRsZSgiR2VtaW5pIFBybyAxLjUiLCBzdWIpCmBgYAoKYGBge3IsIGZpZy53aWR0aD0zLCBmaWcuaGVpZ2h0PTMuNX0Kc3ViIDwtICJJQ0QgY29udmVydGVkIHJlc3BvbnNlcyIKY3VtdWxhdGl2ZV9mcmVxdWVuY3lfcGxvdChkZl9ncHQzLjVfaWNkKSRwbG90K2dndGl0bGUoIkdQVDMgSUNEIiwgc3ViKQpjdW11bGF0aXZlX2ZyZXF1ZW5jeV9wbG90KGRmX2dwdDQuMF9pY2QpJHBsb3QrZ2d0aXRsZSgiR1BUNCBJQ0QiLCBzdWIpCmN1bXVsYXRpdmVfZnJlcXVlbmN5X3Bsb3QoZGZfY2xhdWRlM19oYWlrdV90MS4wX2ljZCkkcGxvdCtnZ3RpdGxlKCJDbGF1ZGUzIEhhaWt1IElDRCIsIHN1YikKY3VtdWxhdGl2ZV9mcmVxdWVuY3lfcGxvdChkZl9jbGF1ZGUzX29wdXNfdDEuMF9pY2QpJHBsb3QrZ2d0aXRsZSgiQ2xhdWRlMyBIYWlrdSBJQ0QiLCBzdWIpCmN1bXVsYXRpdmVfZnJlcXVlbmN5X3Bsb3QoZGZfZ2VtaW5pMS4wX3Byb190MS4wX2ljZCkkcGxvdCtnZ3RpdGxlKCJHZW1pbmkgUHJvIDEuMCBJQ0QiLCBzdWIpCmN1bXVsYXRpdmVfZnJlcXVlbmN5X3Bsb3QoZGZfZ2VtaW5pMS41X3Byb190MS4wX2ljZCkkcGxvdCtnZ3RpdGxlKCJHZW1pbmkgUHJvIDEuMCBJQ0QiLCBzdWIpCmBgYAoKCmBgYHtyLCBmaWcud2lkdGg9NCwgZmlnLmhlaWdodD0zLjV9CnBsdF9mcmVxIDwtIG11bHRpX2N1bXVsYXRpdmVfZnJlcXVlbmN5X3Bsb3QoCiAgbl9kaWFnbm9zZXMgPSAyNSwKICBkaXN0cmlidXRpb25fdmlzID0gInBvaW50cyIsCiAgZGZfZ3B0My41LAogIGRmX2dwdDQuMCwKICBkZl9jbGF1ZGUzX2hhaWt1X3QxLjAsCiAgZGZfY2xhdWRlM19vcHVzX3QxLjAsCiAgZGZfZ2VtaW5pMS4wX3Byb190MS4wLAogIGRmX2dlbWluaTEuNV9wcm9fdDEuMAopICsKICBnZ3RpdGxlKCJPcmlnaW5hbCByZXNwb25zZXMiKQoKcGx0X2ZyZXEKcGx0X2ZyZXEkZGF0YSAlPiUgc3VtbWFyaXNlKGZyZXEgPSBtZWFuKHRvdGFsX2ZyZXF1ZW5jeSksIC5ieSA9ICJjcml0ZXJpYSIpCmBgYAoKYGBge3IsIGZpZy53aWR0aD00LCBmaWcuaGVpZ2h0PTMuNX0KcGx0X2ZyZXFfaWNkIDwtIG11bHRpX2N1bXVsYXRpdmVfZnJlcXVlbmN5X3Bsb3QoCiAgbl9kaWFnbm9zZXMgPSAyNSwKICBkaXN0cmlidXRpb25fdmlzID0gInBvaW50cyIsCiAgZGZfZ3B0My41X2ljZCwKICBkZl9ncHQ0LjBfaWNkLAogIGRmX2NsYXVkZTNfaGFpa3VfdDEuMF9pY2QsCiAgZGZfY2xhdWRlM19vcHVzX3QxLjBfaWNkLAogIGRmX2dlbWluaTEuMF9wcm9fdDEuMF9pY2QsCiAgZGZfZ2VtaW5pMS41X3Byb190MS4wX2ljZAopICsKICBnZ3RpdGxlKCJJQ0QgY29udmVydGVkIHJlc3BvbnNlcyIpCgpwbHRfZnJlcV9pY2QKcGx0X2ZyZXFfaWNkJGRhdGEgJT4lIHN1bW1hcmlzZShmcmVxID0gbWVhbih0b3RhbF9mcmVxdWVuY3kpLCAuYnkgPSAiY3JpdGVyaWEiKQpgYGAKCiMgRGlhZ25vc2lzIHJhbmsgdGFibGUKCmBgYHtyfQpkaWFnbm9zaXNfcmFua190YWJsZShkZl9ncHQzLjUsICJtYXN0IHxtYXN0b2N8YW5hcGh5bGF4aXMiKSAlPiUgbXV0YXRlKGRpYWdub3NpcyA9IHN1YnN0cihkaWFnbm9zaXMsIDEsIDYwKSkKZGlhZ25vc2lzX3JhbmtfdGFibGUoZGZfZ3B0NC4wLCAibWFzdCB8bWFzdG9jfGFuYXBoeWxheGlzIikgJT4lIG11dGF0ZShkaWFnbm9zaXMgPSBzdWJzdHIoZGlhZ25vc2lzLCAxLCA2MCkpIApkaWFnbm9zaXNfcmFua190YWJsZShkZl9jbGF1ZGUzX2hhaWt1X3QxLjAsICJtYXN0IHxtYXN0b2N8YW5hcGh5bGF4aXMiKSAlPiUgbXV0YXRlKGRpYWdub3NpcyA9IHN1YnN0cihkaWFnbm9zaXMsIDEsIDYwKSkgCmRpYWdub3Npc19yYW5rX3RhYmxlKGRmX2NsYXVkZTNfb3B1c190MS4wLCAibWFzdCB8bWFzdG9jfGFuYXBoeWxheGlzIikgJT4lIG11dGF0ZShkaWFnbm9zaXMgPSBzdWJzdHIoZGlhZ25vc2lzLCAxLCA2MCkpIApkaWFnbm9zaXNfcmFua190YWJsZShkZl9nZW1pbmkxLjBfcHJvX3QxLjAsICJtYXN0IHxtYXN0b2N8YW5hcGh5bGF4aXMiKSAlPiUgbXV0YXRlKGRpYWdub3NpcyA9IHN1YnN0cihkaWFnbm9zaXMsIDEsIDYwKSkgCmRpYWdub3Npc19yYW5rX3RhYmxlKGRmX2dlbWluaTEuNV9wcm9fdDEuMCwgIm1hc3QgfG1hc3RvY3xhbmFwaHlsYXhpcyIpICU+JSBtdXRhdGUoZGlhZ25vc2lzID0gc3Vic3RyKGRpYWdub3NpcywgMSwgNjApKSAKYGBgCmBgYHtyfQpkaWFnbm9zaXNfcmFua190YWJsZShkZl9ncHQzLjVfaWNkLCAibWFzdCB8bWFzdG9jfGFuYXBoeWxheGlzIikgJT4lIG11dGF0ZShkaWFnbm9zaXMgPSBzdWJzdHIoZGlhZ25vc2lzLCAxLCA2MCkpIApkaWFnbm9zaXNfcmFua190YWJsZShkZl9ncHQ0LjBfaWNkLCAibWFzdCB8bWFzdG9jfGFuYXBoeWxheGlzIikgJT4lIG11dGF0ZShkaWFnbm9zaXMgPSBzdWJzdHIoZGlhZ25vc2lzLCAxLCA2MCkpIApkaWFnbm9zaXNfcmFua190YWJsZShkZl9jbGF1ZGUzX2hhaWt1X3QxLjBfaWNkLCAibWFzdCB8bWFzdG9jfGFuYXBoeWxheGlzIikgJT4lIG11dGF0ZShkaWFnbm9zaXMgPSBzdWJzdHIoZGlhZ25vc2lzLCAxLCA2MCkpIApkaWFnbm9zaXNfcmFua190YWJsZShkZl9jbGF1ZGUzX29wdXNfdDEuMF9pY2QsICJtYXN0IHxtYXN0b2N8YW5hcGh5bGF4aXMiKSAlPiUgbXV0YXRlKGRpYWdub3NpcyA9IHN1YnN0cihkaWFnbm9zaXMsIDEsIDYwKSkgCmRpYWdub3Npc19yYW5rX3RhYmxlKGRmX2dlbWluaTEuMF9wcm9fdDEuMF9pY2QsICJtYXN0IHxtYXN0b2N8YW5hcGh5bGF4aXMiKSAlPiUgbXV0YXRlKGRpYWdub3NpcyA9IHN1YnN0cihkaWFnbm9zaXMsIDEsIDYwKSkgCmRpYWdub3Npc19yYW5rX3RhYmxlKGRmX2dlbWluaTEuNV9wcm9fdDEuMF9pY2QsICJtYXN0IHxtYXN0b2N8YW5hcGh5bGF4aXMiKSAlPiUgbXV0YXRlKGRpYWdub3NpcyA9IHN1YnN0cihkaWFnbm9zaXMsIDEsIDYwKSkgCmBgYAoKCmBgYHtyfQpyYW5rX3RhYmxlIDwtCiAgbXVsdGlfZGlhZ25vc2lzX3JhbmtfdGFibGUoCiAgICBzZWFyY2hfcGF0dGVybiA9ICJUNzhcXC4yIHxENDdcXC4wMiB8RDg5XFwuNDEgfEQ4OVxcLjQ5IHxEODlcXC40ICIsCiAgICBkZl9ncHQzLjVfaWNkLAogICAgZGZfZ3B0NC4wX2ljZCwKICAgIGRmX2NsYXVkZTNfaGFpa3VfdDEuMF9pY2QsCiAgICBkZl9jbGF1ZGUzX29wdXNfdDEuMF9pY2QsCiAgICBkZl9nZW1pbmkxLjBfcHJvX3QxLjBfaWNkLAogICAgZGZfZ2VtaW5pMS41X3Byb190MS4wX2ljZAogICkKcmFua190YWJsZSAgCmBgYAoKYGBge3J9CnJhbmtfdGFibGUgJT4lIAogIGZsZXh0YWJsZSgpICU+JSAKICB3aWR0aCh3aWR0aCA9IDMwKSAlPiUgCiAgYWxpZ24oaiA9IDI6MywgYWxpZ24gPSAiY2VudGVyIiwgcGFydCA9ICJhbGwiKQpgYGAKCiMgRGl2ZXJzaXR5CgpgYGB7ciwgZmlnLndpZHRoPTQsIGZpZy5oZWlnaHQ9My41fQptdWx0aV9zaGFubm9uX3Bsb3QoCiAgZGlzdHJpYnV0aW9uX3ZpcyA9ICJwb2ludHMiLAogIHdyYXBfd2lkdGggPSA0NSwKICBuX2RpYWcgPSAyNSwKICBkZl9ncHQzLjUsCiAgZGZfZ3B0NC4wLAogIGRmX2NsYXVkZTNfaGFpa3VfdDEuMCwKICBkZl9jbGF1ZGUzX29wdXNfdDEuMCwKICBkZl9nZW1pbmkxLjBfcHJvX3QxLjAsCiAgZGZfZ2VtaW5pMS41X3Byb190MS4wCikKYGBgCgoKYGBge3IsIGZpZy53aWR0aD00LCBmaWcuaGVpZ2h0PTMuNX0KcGx0X2Rpdl9pY2QgPC0gbXVsdGlfc2hhbm5vbl9wbG90KAogIGRpc3RyaWJ1dGlvbl92aXMgPSAicG9pbnRzIiwKICB3cmFwX3dpZHRoID0gNDUsCiAgbl9kaWFnID0gMjUsCiAgZGZfZ3B0My41X2ljZCwKICBkZl9ncHQ0LjBfaWNkLAogIGRmX2NsYXVkZTNfaGFpa3VfdDEuMF9pY2QsCiAgZGZfY2xhdWRlM19vcHVzX3QxLjBfaWNkLAogIGRmX2dlbWluaTEuMF9wcm9fdDEuMF9pY2QsCiAgZGZfZ2VtaW5pMS41X3Byb190MS4wX2ljZAopCgpwbHRfZGl2X2ljZApwbHRfZGl2X2ljZCRkYXRhICU+JSBzdW1tYXJpc2Uoc2hhbm5vbj1tZWFuKHNoYW5ub24pLC5ieT0iY3JpdGVyaWEiKQpleHRyYWN0X2dncHVicl9wdmFsdWVzKHBsdF9kaXZfaWNkKSAgCmBgYAoKIyBTaW1pbGFyaXR5CgpgYGB7ciwgZmlnLndpZHRoPTQuMjUsIGZpZy5oZWlnaHQ9My41fQpkaWFnbm9zaXNfc2ltaWxhcml0eV9oZWF0bWFwKGRmX2dwdDMuNSwgbWV0aG9kID0gImJyYXkiKQpkaWFnbm9zaXNfc2ltaWxhcml0eV9oZWF0bWFwKGRmX2dwdDQuMCwgbWV0aG9kID0gImJyYXkiKQpkaWFnbm9zaXNfc2ltaWxhcml0eV9oZWF0bWFwKGRmX2NsYXVkZTNfaGFpa3VfdDEuMCwgbWV0aG9kID0gImJyYXkiKQpkaWFnbm9zaXNfc2ltaWxhcml0eV9oZWF0bWFwKGRmX2NsYXVkZTNfb3B1c190MS4wLCBtZXRob2QgPSAiYnJheSIpCmRpYWdub3Npc19zaW1pbGFyaXR5X2hlYXRtYXAoZGZfZ2VtaW5pMS4wX3Byb190MS4wLCBtZXRob2QgPSAiYnJheSIpCmRpYWdub3Npc19zaW1pbGFyaXR5X2hlYXRtYXAoZGZfZ2VtaW5pMS41X3Byb190MS4wLCBtZXRob2QgPSAiYnJheSIpCmBgYApgYGB7ciwgZmlnLndpZHRoPTQuMjUsIGZpZy5oZWlnaHQ9My41fQpkaWFnbm9zaXNfc2ltaWxhcml0eV9oZWF0bWFwKGRmX2dwdDMuNV9pY2QsIG1ldGhvZCA9ICJicmF5IikKZGlhZ25vc2lzX3NpbWlsYXJpdHlfaGVhdG1hcChkZl9ncHQ0LjBfaWNkLCBtZXRob2QgPSAiYnJheSIpCmRpYWdub3Npc19zaW1pbGFyaXR5X2hlYXRtYXAoZGZfY2xhdWRlM19oYWlrdV90MS4wX2ljZCwgbWV0aG9kID0gImJyYXkiKQpkaWFnbm9zaXNfc2ltaWxhcml0eV9oZWF0bWFwKGRmX2NsYXVkZTNfb3B1c190MS4wX2ljZCwgbWV0aG9kID0gImJyYXkiKQpkaWFnbm9zaXNfc2ltaWxhcml0eV9oZWF0bWFwKGRmX2dlbWluaTEuMF9wcm9fdDEuMF9pY2QsIG1ldGhvZCA9ICJicmF5IikKZGlhZ25vc2lzX3NpbWlsYXJpdHlfaGVhdG1hcChkZl9nZW1pbmkxLjVfcHJvX3QxLjBfaWNkLCBtZXRob2QgPSAiYnJheSIpCmBgYAoKYGBge3IsIGZpZy53aWR0aD00LjI1LCBmaWcuaGVpZ2h0PTMuNX0KbXVsdGlfZGlhZ25vc2lzX3NpbWlsYXJpdHlfaGVhdG1hcCgKICBtZXRob2QgPSAiYnJheSIsCiAgc2hvd19kZW5kID0gRiwKICBsYWJlbF9zaXplID0gNiwKICB0aXRsZV9zaXplID0gOSwKICBkZl9ncHQzLjUsCiAgZGZfZ3B0NC4wLAogIGRmX2NsYXVkZTNfaGFpa3VfdDEuMCwKICBkZl9jbGF1ZGUzX29wdXNfdDEuMCwKICBkZl9nZW1pbmkxLjBfcHJvX3QxLjAsCiAgZGZfZ2VtaW5pMS41X3Byb190MS4wCikKYGBgCgpgYGB7ciwgZmlnLndpZHRoPTQuMjUsIGZpZy5oZWlnaHQ9My41fQptdWx0aV9kaWFnbm9zaXNfc2ltaWxhcml0eV9oZWF0bWFwKAogIG1ldGhvZCA9ICJicmF5IiwKICBzaG93X2RlbmQgPSBGLAogIGxhYmVsX3NpemUgPSA2LAogIHRpdGxlX3NpemUgPSA5LAogIGRmX2dwdDMuNV9pY2QsCiAgZGZfZ3B0NC4wX2ljZCwKICBkZl9jbGF1ZGUzX2hhaWt1X3QxLjBfaWNkLAogIGRmX2NsYXVkZTNfb3B1c190MS4wX2ljZCwKICBkZl9nZW1pbmkxLjBfcHJvX3QxLjBfaWNkLAogIGRmX2dlbWluaTEuNV9wcm9fdDEuMF9pY2QKKQpgYGAKLSBCcmF5LUN1cnRpcyBzaW1pbGFyaXR5IG1lYXN1cmVzIHRoZSBzaW1pbGFyaXR5IG9mIGEgZ2l2ZW4gZGlhZ25vc3RpYyBjcml0ZXJpYeKAmXMgc2V0IG9mIGFsdGVybmF0aXZlIGRpYWdub3NlcyBhbG9uZyB3aXRoIHRoZWlyIGZyZXF1ZW5jaWVzLgotIFRoaXMgZGVtb25zdHJhdGVzIHRoYXQgU0xFIGNyaXRlcmlhIHJlc3VsdHMgaW4gYSB2ZXJ5IHNpbWlsYXIgc2V0IGFuZCBmcmVxdWVuY3kgb2YgZGlhZ25vc2VzLCB3aGlsZSB0aGUgZGlhZ25vc2VzIGFzc29jaWF0ZWQgd2l0aCB0d28gTUNBUyBjcml0ZXJpYSBhcmUgYXMgZGlmZmVyZW50IGZyb20gZWFjaCBvdGhlciBhcyB0aGV5IGFyZSBmcm9tIHRob3NlIGdlbmVyYXRlZCBieSB0aGUgY3JpdGVyaWEgb2Ygb3RoZXIgY29uZGl0aW9ucy4KCiMjIyBQQ0EKCmBgYHtyLCBmaWcud2lkdGg9NC4yNSwgZmlnLmhlaWdodD0zLjV9CmRpYWdub3Npc19wY2FfcGxvdChkZl9ncHQzLjUpICsgZ2d0aXRsZSgiR1BUMyIpCmRpYWdub3Npc19wY2FfcGxvdChkZl9ncHQ0LjApICsgZ2d0aXRsZSgiR1BUNCIpCmRpYWdub3Npc19wY2FfcGxvdChkZl9jbGF1ZGUzX2hhaWt1X3QxLjApICsgZ2d0aXRsZSgiQ2xhdWRlIEhhaWt1IikKZGlhZ25vc2lzX3BjYV9wbG90KGRmX2NsYXVkZTNfb3B1c190MS4wKSArIGdndGl0bGUoIkNsYXVkZSBPcHVzIikKZGlhZ25vc2lzX3BjYV9wbG90KGRmX2dlbWluaTEuMF9wcm9fdDEuMCkgKyBnZ3RpdGxlKCJHZW1pbmkiKQpkaWFnbm9zaXNfcGNhX3Bsb3QoZGZfZ2VtaW5pMS41X3Byb190MS4wKSArIGdndGl0bGUoIkdlbWluaSIpCmBgYAoKCmBgYHtyfQpkZiA8LSBsaXN0TihkZl9ncHQzLjVfaWNkLCBkZl9ncHQ0LjBfaWNkLCBkZl9jbGF1ZGUzX2hhaWt1X3QxLjBfaWNkLCBkZl9jbGF1ZGUzX29wdXNfdDEuMF9pY2QsIGRmX2dlbWluaTEuMF9wcm9fdDEuMF9pY2QsIGRmX2dlbWluaTEuNV9wcm9fdDEuMF9pY2QpICU+JSAKICBtYXBwbHkoZnVuY3Rpb24oeCx5KSB7bXV0YXRlKHgsIG1vZGVsPXkpfSwgLiwgbmFtZXMoLiksIFNJTVBMSUZZID0gRikgJT4lIAogIGJpbmRfcm93cygpICU+JSAKICBjb3VudChtb2RlbCwgY3JpdGVyaWEsIGRpYWdub3NpcykgJT4lIAogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSAiZGlhZ25vc2lzIiwgdmFsdWVzX2Zyb20gPSAibiIsIHZhbHVlc19maWxsID0gMCkgJT4lIAogIHVuaXRlKGlkLCBtb2RlbCwgY3JpdGVyaWEsIHNlcCA9ICJfXyIpICU+JSAKICBjb2x1bW5fdG9fcm93bmFtZXMoImlkIikgJT4lIAogIHByY29tcChzY2FsZS4gPSBGKQoKYXMuZGF0YS5mcmFtZShkZiR4KSAlPiUgCiAgICByb3duYW1lc190b19jb2x1bW4oImlkIikgJT4lIAogIHNlcGFyYXRlKGlkLCBpbnRvID0gYygibW9kZWwiLCAiY3JpdGVyaWEiKSwgc2VwID0gIl9fIikgJT4lIAogIGZvcm1hdF9jcml0ZXJpYSgpICU+JSAKICBmb3JtYXRfbW9kZWxzKCkgJT4lIAogIGdncGxvdChhZXMoeCA9IFBDMSwgeSA9IFBDMiwgY29sb3IgPSBjcml0ZXJpYSkpKwogICAgZ2VvbV9wb2ludCgpKwogICAgIyBnZ3JlcGVsOjpnZW9tX2xhYmVsX3JlcGVsKCkgKwogICAgdGhlbWVfYncoKSArCiAgc2NhbGVfY29sb3JfYnJld2VyKHBhbGV0dGUgPSAiRGFyazIiKQpgYGAKCiMgUHJlY2lzaW9uCgotIFByZWNpc2lvbiByZXByZXNlbnRzIGhvdyBzaW1pbGFyIGVhY2ggaXRlcmF0aW9uIG9mIGEgMTAtcG9pbnQgZGlmZmVyZW50aWFsIGRpYWdub3NpcyBpcyB3aXRoIGFsbCBvdGhlciBkaWZmZXJlbnRpYWwgZGlhZ25vc2VzIGZyb20gdGhlIHNhbWUgc2V0IG9mIGNyaXRlcmlhLiAKLSBJLmUuIGhvdyByZXByb2R1Y2libGUgdGhlIDEwLXBvaW50IGRpZmZlcmVudGlhbCBkaWFnbm9zaXMgaXMgZm9yIGVhY2ggY3JpdGVyaWEKLSBNZWFzdXJlZCBieSBvYnRhaW5pbmcgdGhlIEJyYXktQ3VydGlzIHNpbWlsYXJpdHkgdmFsdWVzIGJldHdlZW4gYWxsIGl0ZXJhdGlvbnMgd2l0aGluIGEgY3JpdGVyaWEKCmBgYHtyLCBldmFsPUZ9CiMgU2NyaXB0IGZvciBjYWxjdWxhdGluZyBhbGwgQnJheS1DdXJ0aXMgc2ltaWxhcml0eSB2YWx1ZXMgd2l0aGluIGEgY3JpdGVyaWEKIyBGb3VuZCBpbiBzb3VyY2UoaGVyZSgic2NyaXB0cy9kaXZlcnNpdHlfYW5hbHlzaXMvY2FsY3VsYXRlX3ByZWNpc2lvbi5SIikpCiMgQ2FsY3VsYXRlIHByZWNpc2lvbgpsaWJyYXJ5KGhlcmUpCnNvdXJjZShoZXJlKCJ1dGlscy9kYXRhX3Byb2Nlc3NpbmcuUiIpKQoKbW9kZWxzIDwtIGxpc3QuZmlsZXMoaGVyZSgiZGF0YS9wcm9jZXNzZWRfZGlhZ25vc2VzIiksIHBhdHRlcm4gPSAiZ3okIikgJT4lIAogIHN0cl9zcGxpdCgiZGlhZ25vc2VzX3xfaWNkfC5jc3YiKSAlPiUgCiAgc2FwcGx5KC4sIGZ1bmN0aW9uKHgpIHhbMl0pICU+JSAKICB1bmlxdWUoKQoKdXNlX2ljZCA8LSBUUlVFCgppZiAodXNlX2ljZCl7bW9kZWxzIDwtIHN0cl9nbHVlKCJ7bW9kZWxzfV9pY2QiKX0KCmZvciAobSBpbiBtb2RlbHMpewogIHByaW50KHNwcmludGYoIlJFQURJTkcgSU4gREFUQSBGT1I6ICVzIiwgbSkpCiAgcmVhZF9wYXRoIDwtIHNwcmludGYoImRhdGEvcHJvY2Vzc2VkX2RpYWdub3Nlcy9kaWFnbm9zZXNfJXMuY3N2Lmd6IiwgbSkKICBkZiA8LSByZWFkX2NzdihoZXJlKHJlYWRfcGF0aCkpCiAgCiAgcHJpbnQoc3ByaW50ZigiQ0FMQ1VMQVRJTkcgUFJFQ0lTSU9OIEZPUjogJXMiLCBtKSkKICBkZiA8LSBjYWxjdWxhdGVfcHJlY2lzaW9uKGRmKQogIAogIHByaW50KHNwcmludGYoIldSSVRJTkcgUFJFQ0lTSU9OIERBVEEgRk9SOiAlcyIsIG0pKQogIG91dF9wYXRoIDwtIHNwcmludGYoImRhdGEvZGl2ZXJzaXR5X2FuYWx5c2lzL2RpYWdub3Npc19wcmVjaXNpb25fJXMuY3N2Lmd6IiwgbSkKICB3cml0ZV9jc3YoZGYsIGhlcmUob3V0X3BhdGgpKQp9CmBgYAoKYGBge3IsIGZpZy53aWR0aD00LCBmaWcuaGVpZ2h0PTMuNX0KcHJlY2lzaW9uX2Rpc3RfdG9fc2ltIDwtIGZ1bmN0aW9uKGRmKXsKICBkZiAlPiUgCiAgICBtdXRhdGUoCiAgICAgIG1lYW4gPSAxLW1lYW4sCiAgICAgIG1heCA9IDEtbWluLAogICAgICBtaW4gPSAxLW1heAogICAgKQp9CgpwbHRfcHJlY2lzaW9uX2ljZCA8LSByZWFkX2NzdihoZXJlKCJkYXRhL2RpdmVyc2l0eV9hbmFseXNpcy9jb21waWxlZF9pY2RfZGlhZ25vc2lzX3ByZWNpc2lvbi5jc3YiKSkgJT4lIAogIHByZWNpc2lvbl9kaXN0X3RvX3NpbSgpICU+JSAKICBmb3JtYXRfY3JpdGVyaWEoKSAlPiUgCiAgZm9ybWF0X21vZGVscygpICU+JQogIGZpbHRlcihtb2RlbCAhPSAiR2VtaW5pIDEuNSBGbGFzaCIpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBjcml0ZXJpYSwgeSA9IG1lYW4pKSsKICB0aGVtZV9idygpKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlPSA0NSwgaGp1c3QgPSAxKSkrCiAgbGFicyh4PSIiLCB5ID0gIkF2ZXJhZ2UgQnJheS1DdXJ0aXMgU2ltaWxhcml0eSIpICsKICBnZ3B1YnI6Omdlb21fcHdjKGFlcyhncm91cCA9IGNyaXRlcmlhKSwgbWV0aG9kID0gIndpbGNveC50ZXN0IiwgcC5hZGp1c3QubWV0aG9kID0gIkJIIiwgaGlkZS5ucyA9IFQsIGxhYmVsID0gInAuYWRqLnNpZ25pZiIsIGJyYWNrZXQubnVkZ2UueSA9IDAuMywgdmp1c3QgPSAwLjYsIHN0ZXAuaW5jcmVhc2UgPSAwLjE0LCB0aXAubGVuZ3RoID0gMC4wMikgKwogIGxhYnMoY29sb3I9TlVMTCkrCiAgc2NhbGVfY29sb3JfYnJld2VyKHBhbGV0dGUgPSAiRGFyazIiKSArCiAgcGxvdF9zZWxlY3RvcigicG9pbnRzIikKCnBsdF9wcmVjaXNpb25faWNkCnBsdF9wcmVjaXNpb25faWNkJGRhdGEgJT4lIHN1bW1hcmlzZShtZWFuID0gbWVhbihtZWFuKSwgLmJ5PSJjcml0ZXJpYSIpIApleHRyYWN0X2dncHVicl9wdmFsdWVzKHBsdF9wcmVjaXNpb25faWNkKSAKYGBgCgoKIyBpTkVYVAoKYGBge3IsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD00fQppbmV4dF9wbG90cyA8LSBmdW5jdGlvbihpbmV4dF9vYmopewogIGZvciAoaSBpbiAxOjMpewogICAgcGx0IDwtIGlORVhUOjpnZ2lORVhUKGluZXh0X29iaiwgdHlwZT1pLCBmYWNldC52YXI9IkFzc2VtYmxhZ2UiLCBjb2xvci52YXI9IkFzc2VtYmxhZ2UiKSArCiAgICAgIHRoZW1lX2NsYXNzaWMoKSArIAogICAgICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZSA9ICJTZXQxIikgKwogICAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSkrCiAgICAgIHNjYWxlX2NvbG9yX2JyZXdlcihwYWxldHRlID0gIkRhcmsyIikKICAgIHByaW50KHBsdCkKICB9Cn0KCnJlYWRSRFMoaGVyZSgiZGF0YS9kaXZlcnNpdHlfYW5hbHlzaXMvbWNhc19pTkVYVF9ncHQ0X2UyNTAwMDAuUkRTIikpICU+JSBpbmV4dF9wbG90cygpCnJlYWRSRFMoaGVyZSgiZGF0YS9kaXZlcnNpdHlfYW5hbHlzaXMvbWNhc19pTkVYVF9kcm9wU2luZ2xlX2dwdDRfZTIwMDAwMC5SRFMiKSkgJT4lIGluZXh0X3Bsb3RzKCkKcmVhZFJEUyhoZXJlKCJkYXRhL2RpdmVyc2l0eV9hbmFseXNpcy9tY2FzX2lORVhUX2Ryb3BTaW5nbGVfcHN1ZWRvTWludXNfZ3B0NF9lMjAwMDAwLlJEUyIpKSAlPiUgaW5leHRfcGxvdHMoKQpgYGAKCgoKYGBge3IsIGZpZy53aWR0aD03LjQsIGZpZy5oZWlnaHQ9Ni41fQojIGN1c3RvbV9sYWJlbGVyIDwtIGZ1bmN0aW9uKHgsIHdyYXBfd2lkdGg9MzMpIHsKIyAgICAgeCAlPiUKIyAgICAgICAgIHN0cl9yZXBsYWNlKCJfX18uKyQiLCAiIikgJT4lCiMgICAgICAgICBzdHJfd3JhcCh3aWR0aCA9IHdyYXBfd2lkdGgpCiMgfQpgYGAKCiMgRmluYWwgcGxvdAoKIyMjIFZlcnNpb24gMQoKYGBge3IsIGZpZy53aWR0aD03LjUsIGZpZy5oZWlnaHQ9OC41LCBtZXNzYWdlID0gRn0Kbl9kaWFnbm9zZXNfYmFyIDwtIDEwCm5fZGlhZ25vc2VzX2FidW5kYW5jZSA8LSA1MApuX2RpYWdub3Nlc19jdW11bGF0aXZlIDwtIDUwCgp0aXRsZV9zaXplIDwtIDkKbGFiZWxfc2l6ZSA8LSA2CmxlZ2VuZF94X3BhZCA8LSA0CmxlZ2VuZF95X3BhZCA8LSAyCgphcHBseV90ZXh0X2Zvcm1hdHRpbmcgPC0gbGlzdCh0aGVtZSgKICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IGxhYmVsX3NpemUpLAogIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IHRpdGxlX3NpemUpLAogIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSBsYWJlbF9zaXplKSwKICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSBsYWJlbF9zaXplKzEpLAogIGxlZ2VuZC5rZXkuaGVpZ2h0ID0gdW5pdCgwLjQsICdjbScpLAogIGxlZ2VuZC5ib3guYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChjb2xvciA9ICJibGFjayIsIHNpemUgPSAxKSwKICBsZWdlbmQubWFyZ2luID0gbWFyZ2luKHQgPSBsZWdlbmRfeV9wYWQsIHIgPSBsZWdlbmRfeF9wYWQsIGIgPSBsZWdlbmRfeV9wYWQsIGwgPSBsZWdlbmRfeF9wYWQqMS4xKSwKICBsZWdlbmQuc3BhY2luZy54ID0gdW5pdCgwLCAnY20nKSwgICAgICAgICAgICAgICAgICAgICAgICAgICAjIEhvcml6b250YWwgc3BhY2luZyBiZXR3ZWVuIGxlZ2VuZCBpdGVtcwogICMgbGVnZW5kLnNwYWNpbmcueSA9IHVuaXQoMCwgJ2NtJyksCiAgIyBsZWdlbmQuYm94LnNwYWNpbmcgPSB1bml0KDAsICJjbSIpCiAgKSkKCnN0cmlwX21hcmdpbiA8LSAxCnN0cmlwX2Zvcm1hdHRpbmcgPC0gbGlzdCh0aGVtZSgKICBzdHJpcC50ZXh0LnggPSBlbGVtZW50X3RleHQobWFyZ2luID0gbWFyZ2luKHQgPSBzdHJpcF9tYXJnaW4sIHIgPSBzdHJpcF9tYXJnaW4sIGIgPSBzdHJpcF9tYXJnaW4sIGwgPSBzdHJpcF9tYXJnaW4pKSwgCiAgc3RyaXAudGV4dC55ID0gZWxlbWVudF90ZXh0KG1hcmdpbiA9IG1hcmdpbih0ID0gc3RyaXBfbWFyZ2luLCByID0gc3RyaXBfbWFyZ2luLCBiID0gc3RyaXBfbWFyZ2luLCBsID0gc3RyaXBfbWFyZ2luKSkKICAjIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QobWFyZ2luID0gbWFyZ2luKHQgPSBzdHJpcF9tYXJnaW4sIHIgPSBzdHJpcF9tYXJnaW4sIGIgPSBzdHJpcF9tYXJnaW4sIGwgPSBzdHJpcF9tYXJnaW4pKQopKQoKcGx0X2RpYWdzIDwtCiAgbXVsdGlfdG9wX2RpYWdub3Npc19wbG90KAogICAgZGlzdHJpYnV0aW9uX3ZpcyA9ICJwb2ludHMiLAogICAgd3JhcF93aWR0aCA9IDU4LAogICAgbl9kaWFnID0gbl9kaWFnbm9zZXNfYmFyLAogICAgZGZfZ3B0My41X2ljZCwKICAgIGRmX2dwdDQuMF9pY2QsCiAgICBkZl9jbGF1ZGUzX2hhaWt1X3QxLjBfaWNkLAogICAgZGZfY2xhdWRlM19vcHVzX3QxLjBfaWNkLAogICAgZGZfZ2VtaW5pMS4wX3Byb190MS4wX2ljZCwKICAgIGRmX2dlbWluaTEuNV9mbGFzaF90MS4wX2ljZAogICkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLCBsZWdlbmQuZGlyZWN0aW9uID0gImhvcml6b250YWwiKSArCiAgYXBwbHlfdGV4dF9mb3JtYXR0aW5nICsKICB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gNi41KSkgKwogIHN0cmlwX2Zvcm1hdHRpbmcgKwogICMgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gYygtMSwwKSkrCiAgdGhlbWUocGFuZWwuc3BhY2luZyA9IHVuaXQoMCwgImxpbmVzIikpICsKICBndWlkZXMoY29sb3IgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gMikpKSAgIyBJbmNyZWFzZSB0aGUgcG9pbnQgc2l6ZSBpbiB0aGUgbGVnZW5kKQogIAoKcGx0X3JhbmsgPC0KICBtdWx0aV9yYW5rZWRfYWJ1bmRhbmNlX3Bsb3QoCiAgICBkZl9ncHQzLjVfaWNkLAogICAgZGZfZ3B0NC4wX2ljZCwKICAgIGRmX2NsYXVkZTNfaGFpa3VfdDEuMF9pY2QsCiAgICBkZl9jbGF1ZGUzX29wdXNfdDEuMF9pY2QsCiAgICBkZl9nZW1pbmkxLjBfcHJvX3QxLjBfaWNkLAogICAgZGZfZ2VtaW5pMS41X3Byb190MS4wX2ljZAogICkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLCBsZWdlbmQuZGlyZWN0aW9uID0gImhvcml6b250YWwiKSArCiAgYXBwbHlfdGV4dF9mb3JtYXR0aW5nICsKICBndWlkZXMoY29sb3IgPSBndWlkZV9sZWdlbmQobmNvbCA9IDIpKQoKcGx0X2N1bXVsYXRpdmUgPC0gbXVsdGlfY3VtdWxhdGl2ZV9mcmVxdWVuY3lfcGxvdCgKICBuX2RpYWdub3NlcyA9IG5fZGlhZ25vc2VzX2N1bXVsYXRpdmUsCiAgZGlzdHJpYnV0aW9uX3ZpcyA9ICJwb2ludHMiLAogIGRmX2dwdDMuNV9pY2QsCiAgZGZfZ3B0NC4wX2ljZCwKICBkZl9jbGF1ZGUzX2hhaWt1X3QxLjBfaWNkLAogIGRmX2NsYXVkZTNfb3B1c190MS4wX2ljZCwKICBkZl9nZW1pbmkxLjBfcHJvX3QxLjBfaWNkCikgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLCBsZWdlbmQuZGlyZWN0aW9uID0gImhvcml6b250YWwiKSArCiAgYXBwbHlfdGV4dF9mb3JtYXR0aW5nICsKICBndWlkZXMoY29sb3IgPSBndWlkZV9sZWdlbmQobmNvbCA9IDIpKSArCiAgbGFicyh5ID0gIkNvbWJpbmVkIGZyZXF1ZW5jeVxub2YgdG9wIDUwIGRpYWdub3NlcyIsIHggPSBOVUxMKQoKcGx0X3NoYW5ub24gPC0gbXVsdGlfc2hhbm5vbl9wbG90KAogIGRpc3RyaWJ1dGlvbl92aXMgPSAicG9pbnRzIiwKICB3cmFwX3dpZHRoID0gNDUsCiAgbl9kaWFnID0gMjUsCiAgZGZfZ3B0My41X2ljZCwKICBkZl9ncHQ0LjBfaWNkLAogIGRmX2NsYXVkZTNfaGFpa3VfdDEuMF9pY2QsCiAgZGZfY2xhdWRlM19vcHVzX3QxLjBfaWNkLAogIGRmX2dlbWluaTEuMF9wcm9fdDEuMF9pY2QsCiAgZGZfZ2VtaW5pMS41X3Byb190MS4wX2ljZAopICsKICBhcHBseV90ZXh0X2Zvcm1hdHRpbmcgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLCBsZWdlbmQuZGlyZWN0aW9uID0gImhvcml6b250YWwiKSArCiAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKG5jb2wgPSAyKSkKCnBsdF9wcmVjaXNpb24gPC0gcmVhZF9jc3YoaGVyZSgiZGF0YS9kaXZlcnNpdHlfYW5hbHlzaXMvY29tcGlsZWRfaWNkX2RpYWdub3Npc19wcmVjaXNpb24uY3N2IikpICU+JSAKICBwcmVjaXNpb25fZGlzdF90b19zaW0oKSAlPiUgCiAgZm9ybWF0X2NyaXRlcmlhKCkgJT4lIAogIGZvcm1hdF9tb2RlbHMoKSAlPiUKICBmaWx0ZXIobW9kZWwgIT0gIkdlbWluaSAxLjUgRmxhc2giKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gY3JpdGVyaWEsIHkgPSBtZWFuKSkrCiAgdGhlbWVfYncoKSsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZT0gNDUsIGhqdXN0ID0gMSkpKwogIGxhYnMoeD0iIiwgeSA9ICJBdmVyYWdlIEJyYXktQ3VydGlzXG5TaW1pbGFyaXR5IikgKwogIGdncHVicjo6Z2VvbV9wd2MoYWVzKGdyb3VwID0gY3JpdGVyaWEpLCBtZXRob2QgPSAid2lsY294LnRlc3QiLCBwLmFkanVzdC5tZXRob2QgPSAiQkgiLCBoaWRlLm5zID0gVCwgbGFiZWwgPSAicC5hZGouc2lnbmlmIiwgYnJhY2tldC5udWRnZS55ID0gMC4zLCB2anVzdCA9IDAuNiwgc3RlcC5pbmNyZWFzZSA9IDAuMTQsIHRpcC5sZW5ndGggPSAwLjAyKSArCiAgbGFicyhjb2xvcj1OVUxMKSsKICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZSA9ICJEYXJrMiIpICsKICBwbG90X3NlbGVjdG9yKCJwb2ludHMiKSArCiAgYXBwbHlfdGV4dF9mb3JtYXR0aW5nICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwgbGVnZW5kLmRpcmVjdGlvbiA9ICJob3Jpem9udGFsIikgKwogIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChuY29sID0gMikpCgpmdWxsX3BsdCA8LSBwbG90X2dyaWQoCiAgCiAgIyMjCiAgcGx0X2RpYWdzLAogICMjIwogIE5VTEwsCiAgcGxvdF9ncmlkKAogICAgICBwbHRfcmFuaywKICAgICAgcGx0X2N1bXVsYXRpdmUsCiAgICAgIHBsdF9zaGFubm9uLAogICAgICBwbHRfcHJlY2lzaW9uLAogICAgICBucm93ID0gMSwgCiAgICAgIGF4aXMgPSAndGInLAogICAgICBhbGlnbiA9ICdoJywKICAgICAgcmVsX3dpZHRocyA9IGMoMSwgMC43LCAwLjcsIDAuNyksCiAgICAgIGxhYmVscyA9IGMoTEVUVEVSU1syOjVdKSwKICAgICAgdmp1c3QgPSAwLjIKICAgICksCiAgbmNvbCA9IDEsCiAgcmVsX2hlaWdodHMgPSBjKDEuMiwgMC4wNSwgMC42NSksCiAgbGFiZWxzID0gYygiQSIsIiIsIiIpCikgIAoKZnVsbF9wbHQKYGBgCgojIyMgVmVyc2lvbiAyCmBgYHtyLCBmaWcud2lkdGg9Ny41LCBmaWcuaGVpZ2h0PTguNSwgbWVzc2FnZSA9IEZ9Cm5fZGlhZ25vc2VzX2JhciA8LSAxMApuX2RpYWdub3Nlc19hYnVuZGFuY2UgPC0gNTAKbl9kaWFnbm9zZXNfY3VtdWxhdGl2ZSA8LSA1MAoKdGl0bGVfc2l6ZSA8LSA5CmxhYmVsX3NpemUgPC0gNgpsZWdlbmRfeF9wYWQgPC0gNApsZWdlbmRfeV9wYWQgPC0gMgoKYXBwbHlfdGV4dF9mb3JtYXR0aW5nIDwtIGxpc3QodGhlbWUoCiAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSBsYWJlbF9zaXplKSwKICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSB0aXRsZV9zaXplKSwKICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gbGFiZWxfc2l6ZSksCiAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gbGFiZWxfc2l6ZSsxKSwKICBsZWdlbmQua2V5LmhlaWdodCA9IHVuaXQoMC40LCAnY20nKSwKICBsZWdlbmQuYm94LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoY29sb3IgPSAiYmxhY2siLCBzaXplID0gMSksCiAgbGVnZW5kLm1hcmdpbiA9IG1hcmdpbih0ID0gbGVnZW5kX3lfcGFkLCByID0gbGVnZW5kX3hfcGFkLCBiID0gbGVnZW5kX3lfcGFkLCBsID0gbGVnZW5kX3hfcGFkKjEuMSksCiAgbGVnZW5kLnNwYWNpbmcueCA9IHVuaXQoMCwgJ2NtJyksICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBIb3Jpem9udGFsIHNwYWNpbmcgYmV0d2VlbiBsZWdlbmQgaXRlbXMKICAjIGxlZ2VuZC5zcGFjaW5nLnkgPSB1bml0KDAsICdjbScpLAogICMgbGVnZW5kLmJveC5zcGFjaW5nID0gdW5pdCgwLCAiY20iKQogICkpCgpzdHJpcF9tYXJnaW4gPC0gMQpzdHJpcF9mb3JtYXR0aW5nIDwtIGxpc3QodGhlbWUoCiAgc3RyaXAudGV4dC54ID0gZWxlbWVudF90ZXh0KG1hcmdpbiA9IG1hcmdpbih0ID0gc3RyaXBfbWFyZ2luLCByID0gc3RyaXBfbWFyZ2luLCBiID0gc3RyaXBfbWFyZ2luLCBsID0gc3RyaXBfbWFyZ2luKSksIAogIHN0cmlwLnRleHQueSA9IGVsZW1lbnRfdGV4dChtYXJnaW4gPSBtYXJnaW4odCA9IHN0cmlwX21hcmdpbiwgciA9IHN0cmlwX21hcmdpbiwgYiA9IHN0cmlwX21hcmdpbiwgbCA9IHN0cmlwX21hcmdpbikpCiAgIyBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KG1hcmdpbiA9IG1hcmdpbih0ID0gc3RyaXBfbWFyZ2luLCByID0gc3RyaXBfbWFyZ2luLCBiID0gc3RyaXBfbWFyZ2luLCBsID0gc3RyaXBfbWFyZ2luKSkKKSkKCnBsdF9kaWFncyA8LQogIG11bHRpX3RvcF9kaWFnbm9zaXNfcGxvdCgKICAgIGRpc3RyaWJ1dGlvbl92aXMgPSAicG9pbnRzIiwKICAgIHdyYXBfd2lkdGggPSA1OCwKICAgIG5fZGlhZyA9IG5fZGlhZ25vc2VzX2JhciwKICAgIGRmX2dwdDMuNV9pY2QsCiAgICBkZl9ncHQ0LjBfaWNkLAogICAgZGZfY2xhdWRlM19oYWlrdV90MS4wX2ljZCwKICAgIGRmX2NsYXVkZTNfb3B1c190MS4wX2ljZCwKICAgIGRmX2dlbWluaTEuMF9wcm9fdDEuMF9pY2QsCiAgICBkZl9nZW1pbmkxLjVfZmxhc2hfdDEuMF9pY2QKICApICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwgbGVnZW5kLmRpcmVjdGlvbiA9ICJob3Jpem9udGFsIikgKwogIGFwcGx5X3RleHRfZm9ybWF0dGluZyArCiAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYuNSkpICsKICBzdHJpcF9mb3JtYXR0aW5nICsKICAjIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9IGMoLTEsMCkpKwogIHRoZW1lKHBhbmVsLnNwYWNpbmcgPSB1bml0KDAsICJsaW5lcyIpKSArCiAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZSA9IDIpLCBucm93ID0gMSkpICAjIEluY3JlYXNlIHRoZSBwb2ludCBzaXplIGluIHRoZSBsZWdlbmQpCiAgCgpwbHRfcmFuayA8LQogIG11bHRpX3JhbmtlZF9hYnVuZGFuY2VfcGxvdCgKICAgIGRmX2dwdDMuNV9pY2QsCiAgICBkZl9ncHQ0LjBfaWNkLAogICAgZGZfY2xhdWRlM19oYWlrdV90MS4wX2ljZCwKICAgIGRmX2NsYXVkZTNfb3B1c190MS4wX2ljZCwKICAgIGRmX2dlbWluaTEuMF9wcm9fdDEuMF9pY2QsCiAgICBkZl9nZW1pbmkxLjVfcHJvX3QxLjBfaWNkCiAgKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gYygwLjcsMC43KSkrCiAgIyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwgbGVnZW5kLmRpcmVjdGlvbiA9ICJob3Jpem9udGFsIikgKwogIGFwcGx5X3RleHRfZm9ybWF0dGluZyArCiAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKG5jb2wgPSAxKSkgKwogIGxhYnMoY29sb3IgPSBOVUxMKQoKcGx0X2N1bXVsYXRpdmUgPC0gbXVsdGlfY3VtdWxhdGl2ZV9mcmVxdWVuY3lfcGxvdCgKICBuX2RpYWdub3NlcyA9IG5fZGlhZ25vc2VzX2N1bXVsYXRpdmUsCiAgZGlzdHJpYnV0aW9uX3ZpcyA9ICJwb2ludHMiLAogIGRmX2dwdDMuNV9pY2QsCiAgZGZfZ3B0NC4wX2ljZCwKICBkZl9jbGF1ZGUzX2hhaWt1X3QxLjBfaWNkLAogIGRmX2NsYXVkZTNfb3B1c190MS4wX2ljZCwKICBkZl9nZW1pbmkxLjBfcHJvX3QxLjBfaWNkCikgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLCBsZWdlbmQuZGlyZWN0aW9uID0gImhvcml6b250YWwiKSArCiAgYXBwbHlfdGV4dF9mb3JtYXR0aW5nICsKICBndWlkZXMoY29sb3IgPSBndWlkZV9sZWdlbmQobmNvbCA9IDIpKSArCiAgbGFicyh5ID0gIkNvbWJpbmVkIGZyZXF1ZW5jeVxub2YgdG9wIDUwIGRpYWdub3NlcyIsIHggPSBOVUxMKQoKcGx0X3NoYW5ub24gPC0gbXVsdGlfc2hhbm5vbl9wbG90KAogIGRpc3RyaWJ1dGlvbl92aXMgPSAicG9pbnRzIiwKICB3cmFwX3dpZHRoID0gNDUsCiAgbl9kaWFnID0gMjUsCiAgZGZfZ3B0My41X2ljZCwKICBkZl9ncHQ0LjBfaWNkLAogIGRmX2NsYXVkZTNfaGFpa3VfdDEuMF9pY2QsCiAgZGZfY2xhdWRlM19vcHVzX3QxLjBfaWNkLAogIGRmX2dlbWluaTEuMF9wcm9fdDEuMF9pY2QsCiAgZGZfZ2VtaW5pMS41X3Byb190MS4wX2ljZAopICsKICBhcHBseV90ZXh0X2Zvcm1hdHRpbmcgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLCBsZWdlbmQuZGlyZWN0aW9uID0gImhvcml6b250YWwiKSArCiAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKG5jb2wgPSAyKSkKCnBsdF9wcmVjaXNpb24gPC0gcmVhZF9jc3YoaGVyZSgiZGF0YS9kaXZlcnNpdHlfYW5hbHlzaXMvY29tcGlsZWRfaWNkX2RpYWdub3Npc19wcmVjaXNpb24uY3N2IikpICU+JSAKICBwcmVjaXNpb25fZGlzdF90b19zaW0oKSAlPiUgCiAgZm9ybWF0X2NyaXRlcmlhKCkgJT4lIAogIGZvcm1hdF9tb2RlbHMoKSAlPiUKICBmaWx0ZXIobW9kZWwgIT0gIkdlbWluaSAxLjUgRmxhc2giKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gY3JpdGVyaWEsIHkgPSBtZWFuKSkrCiAgdGhlbWVfYncoKSsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZT0gNDUsIGhqdXN0ID0gMSkpKwogIGxhYnMoeD0iIiwgeSA9ICJBdmVyYWdlIEJyYXktQ3VydGlzXG5TaW1pbGFyaXR5IikgKwogIGdncHVicjo6Z2VvbV9wd2MoYWVzKGdyb3VwID0gY3JpdGVyaWEpLCBtZXRob2QgPSAid2lsY294LnRlc3QiLCBwLmFkanVzdC5tZXRob2QgPSAiQkgiLCBoaWRlLm5zID0gVCwgbGFiZWwgPSAicC5hZGouc2lnbmlmIiwgYnJhY2tldC5udWRnZS55ID0gMC4zLCB2anVzdCA9IDAuNiwgc3RlcC5pbmNyZWFzZSA9IDAuMTQsIHRpcC5sZW5ndGggPSAwLjAyKSArCiAgbGFicyhjb2xvcj1OVUxMKSsKICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZSA9ICJEYXJrMiIpICsKICBwbG90X3NlbGVjdG9yKCJwb2ludHMiKSArCiAgYXBwbHlfdGV4dF9mb3JtYXR0aW5nICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwgbGVnZW5kLmRpcmVjdGlvbiA9ICJob3Jpem9udGFsIikgKwogIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChuY29sID0gMikpCgpmdWxsX3BsdCA8LSBwbG90X2dyaWQoCiAgCiAgIyMjCiAgcGx0X2RpYWdzLAogICMjIwogIE5VTEwsCiAgcGxvdF9ncmlkKAogICAgICBwbHRfcmFuaywKICAgICAgcGxvdF9ncmlkKAogICAgICAgIHBsb3RfZ3JpZCgKICAgICAgICAgIHBsdF9zaGFubm9uKyB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSwKICAgICAgICAgIHBsdF9wcmVjaXNpb24rIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpLAogICAgICAgICAgbnJvdyA9IDEsCiAgICAgICAgICBheGlzID0gJ3RiJywKICAgICAgICAgIGFsaWduID0gJ2gnCiAgICAgICAgKSwKICAgICAgICBnZXRfbGVnZW5kKHBsdF9zaGFubm9uKyBndWlkZXMoY29sb3IgPSBndWlkZV9sZWdlbmQocm93ID0gMSkpKSwKICAgICAgICBuY29sID0gMSwKICAgICAgICByZWxfaGVpZ2h0cyA9IGMoMSwwLjEpCiAgICAgICksCiAgICAgIG5yb3cgPSAxLCAKICAgICAgcmVsX3dpZHRocyA9IGMoMSwxKSwKICAgICAgIyBsYWJlbHMgPSBjKExFVFRFUlNbMjo1XSksCiAgICAgIHZqdXN0ID0gMC4yCiAgICApLAogIG5jb2wgPSAxLAogIHJlbF9oZWlnaHRzID0gYygxLjIsIDAuMDUsIDAuNjUpLAogIGxhYmVscyA9IGMoIkEiLCIiLCIiKQopICAKCmZ1bGxfcGx0CmBgYAoKIyMjIFZlcnNpb24gMwpgYGB7ciwgZmlnLndpZHRoPTcuNSwgZmlnLmhlaWdodD04LjUsIG1lc3NhZ2UgPSBGfQpuX2RpYWdub3Nlc19iYXIgPC0gMTAKbl9kaWFnbm9zZXNfYWJ1bmRhbmNlIDwtIDUwCm5fZGlhZ25vc2VzX2N1bXVsYXRpdmUgPC0gNTAKCnRpdGxlX3NpemUgPC0gOQpsYWJlbF9zaXplIDwtIDYKbGVnZW5kX3hfcGFkIDwtIDQKbGVnZW5kX3lfcGFkIDwtIDIKCmFwcGx5X3RleHRfZm9ybWF0dGluZyA8LSBsaXN0KHRoZW1lKAogIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gbGFiZWxfc2l6ZSksCiAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gdGl0bGVfc2l6ZSksCiAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IGxhYmVsX3NpemUpLAogIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IGxhYmVsX3NpemUrMSksCiAgbGVnZW5kLmtleS5oZWlnaHQgPSB1bml0KDAuNCwgJ2NtJyksCiAgbGVnZW5kLmJveC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGNvbG9yID0gImJsYWNrIiwgc2l6ZSA9IDEpLAogIGxlZ2VuZC5tYXJnaW4gPSBtYXJnaW4odCA9IGxlZ2VuZF95X3BhZCwgciA9IGxlZ2VuZF94X3BhZCwgYiA9IGxlZ2VuZF95X3BhZCwgbCA9IGxlZ2VuZF94X3BhZCoxLjEpLAogIGxlZ2VuZC5zcGFjaW5nLnggPSB1bml0KDAsICdjbScpLCAgICAgICAgICAgICAgICAgICAgICAgICAgICMgSG9yaXpvbnRhbCBzcGFjaW5nIGJldHdlZW4gbGVnZW5kIGl0ZW1zCiAgIyBsZWdlbmQuc3BhY2luZy55ID0gdW5pdCgwLCAnY20nKSwKICAjIGxlZ2VuZC5ib3guc3BhY2luZyA9IHVuaXQoMCwgImNtIikKICApKQoKc3RyaXBfbWFyZ2luIDwtIDEKc3RyaXBfZm9ybWF0dGluZyA8LSBsaXN0KHRoZW1lKAogIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfdGV4dChtYXJnaW4gPSBtYXJnaW4odCA9IHN0cmlwX21hcmdpbiwgciA9IHN0cmlwX21hcmdpbiwgYiA9IHN0cmlwX21hcmdpbiwgbCA9IHN0cmlwX21hcmdpbikpLCAKICBzdHJpcC50ZXh0LnkgPSBlbGVtZW50X3RleHQobWFyZ2luID0gbWFyZ2luKHQgPSBzdHJpcF9tYXJnaW4sIHIgPSBzdHJpcF9tYXJnaW4sIGIgPSBzdHJpcF9tYXJnaW4sIGwgPSBzdHJpcF9tYXJnaW4pKQogICMgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChtYXJnaW4gPSBtYXJnaW4odCA9IHN0cmlwX21hcmdpbiwgciA9IHN0cmlwX21hcmdpbiwgYiA9IHN0cmlwX21hcmdpbiwgbCA9IHN0cmlwX21hcmdpbikpCikpCgpwbHRfZGlhZ3MgPC0KICBtdWx0aV90b3BfZGlhZ25vc2lzX3Bsb3QoCiAgICBkaXN0cmlidXRpb25fdmlzID0gInBvaW50cyIsCiAgICB3cmFwX3dpZHRoID0gNTgsCiAgICBuX2RpYWcgPSBuX2RpYWdub3Nlc19iYXIsCiAgICBkZl9ncHQzLjVfaWNkLAogICAgZGZfZ3B0NC4wX2ljZCwKICAgIGRmX2NsYXVkZTNfaGFpa3VfdDEuMF9pY2QsCiAgICBkZl9jbGF1ZGUzX29wdXNfdDEuMF9pY2QsCiAgICBkZl9nZW1pbmkxLjBfcHJvX3QxLjBfaWNkLAogICAgZGZfZ2VtaW5pMS41X2ZsYXNoX3QxLjBfaWNkCiAgKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsIGxlZ2VuZC5kaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIpICsKICBhcHBseV90ZXh0X2Zvcm1hdHRpbmcgKwogIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSA2LjUpKSArCiAgc3RyaXBfZm9ybWF0dGluZyArCiAgIyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSBjKC0xLDApKSsKICB0aGVtZShwYW5lbC5zcGFjaW5nID0gdW5pdCgwLCAibGluZXMiKSkgKwogIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KHNpemUgPSAyKSwgbnJvdyA9IDEpKSAgIyBJbmNyZWFzZSB0aGUgcG9pbnQgc2l6ZSBpbiB0aGUgbGVnZW5kKQogIAoKcGx0X3JhbmsgPC0KICBtdWx0aV9yYW5rZWRfYWJ1bmRhbmNlX3Bsb3QoCiAgICBkZl9ncHQzLjVfaWNkLAogICAgZGZfZ3B0NC4wX2ljZCwKICAgIGRmX2NsYXVkZTNfaGFpa3VfdDEuMF9pY2QsCiAgICBkZl9jbGF1ZGUzX29wdXNfdDEuMF9pY2QsCiAgICBkZl9nZW1pbmkxLjBfcHJvX3QxLjBfaWNkLAogICAgZGZfZ2VtaW5pMS41X3Byb190MS4wX2ljZAogICkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9IGMoMC43LDAuNykpKwogICMgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsIGxlZ2VuZC5kaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIpICsKICBhcHBseV90ZXh0X2Zvcm1hdHRpbmcgKwogIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChuY29sID0gMSkpICsKICBsYWJzKGNvbG9yID0gTlVMTCkKCnBsdF9jdW11bGF0aXZlIDwtIG11bHRpX2N1bXVsYXRpdmVfZnJlcXVlbmN5X3Bsb3QoCiAgbl9kaWFnbm9zZXMgPSBuX2RpYWdub3Nlc19jdW11bGF0aXZlLAogIGRpc3RyaWJ1dGlvbl92aXMgPSAicG9pbnRzIiwKICBkZl9ncHQzLjVfaWNkLAogIGRmX2dwdDQuMF9pY2QsCiAgZGZfY2xhdWRlM19oYWlrdV90MS4wX2ljZCwKICBkZl9jbGF1ZGUzX29wdXNfdDEuMF9pY2QsCiAgZGZfZ2VtaW5pMS4wX3Byb190MS4wX2ljZAopICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwgbGVnZW5kLmRpcmVjdGlvbiA9ICJob3Jpem9udGFsIikgKwogIGFwcGx5X3RleHRfZm9ybWF0dGluZyArCiAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKG5jb2wgPSAyKSkgKwogIGxhYnMoeSA9ICJDb21iaW5lZCBmcmVxdWVuY3lcbm9mIHRvcCA1MCBkaWFnbm9zZXMiLCB4ID0gTlVMTCkKCnBsdF9zaGFubm9uIDwtIG11bHRpX3NoYW5ub25fcGxvdCgKICBkaXN0cmlidXRpb25fdmlzID0gInBvaW50cyIsCiAgd3JhcF93aWR0aCA9IDQ1LAogIG5fZGlhZyA9IDI1LAogIGRmX2dwdDMuNV9pY2QsCiAgZGZfZ3B0NC4wX2ljZCwKICBkZl9jbGF1ZGUzX2hhaWt1X3QxLjBfaWNkLAogIGRmX2NsYXVkZTNfb3B1c190MS4wX2ljZCwKICBkZl9nZW1pbmkxLjBfcHJvX3QxLjBfaWNkLAogIGRmX2dlbWluaTEuNV9wcm9fdDEuMF9pY2QKKSArCiAgYXBwbHlfdGV4dF9mb3JtYXR0aW5nICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwgbGVnZW5kLmRpcmVjdGlvbiA9ICJob3Jpem9udGFsIikgKwogIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChuY29sID0gMikpCgpwbHRfcHJlY2lzaW9uIDwtIHJlYWRfY3N2KGhlcmUoImRhdGEvZGl2ZXJzaXR5X2FuYWx5c2lzL2NvbXBpbGVkX2ljZF9kaWFnbm9zaXNfcHJlY2lzaW9uLmNzdiIpKSAlPiUgCiAgcHJlY2lzaW9uX2Rpc3RfdG9fc2ltKCkgJT4lIAogIGZvcm1hdF9jcml0ZXJpYSgpICU+JSAKICBmb3JtYXRfbW9kZWxzKCkgJT4lCiAgZmlsdGVyKG1vZGVsICE9ICJHZW1pbmkgMS41IEZsYXNoIikgJT4lIAogIGdncGxvdChhZXMoeCA9IGNyaXRlcmlhLCB5ID0gbWVhbikpKwogIHRoZW1lX2J3KCkrCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGU9IDQ1LCBoanVzdCA9IDEpKSsKICBsYWJzKHg9IiIsIHkgPSAiTWVhbiBCcmF5LUN1cnRpcyBTaW1pbGFyaXR5IikgKwogIGdncHVicjo6Z2VvbV9wd2MoYWVzKGdyb3VwID0gY3JpdGVyaWEpLCBtZXRob2QgPSAid2lsY294LnRlc3QiLCBwLmFkanVzdC5tZXRob2QgPSAiQkgiLCBoaWRlLm5zID0gVCwgbGFiZWwgPSAicC5hZGouc2lnbmlmIiwgYnJhY2tldC5udWRnZS55ID0gMC4zLCB2anVzdCA9IDAuNiwgc3RlcC5pbmNyZWFzZSA9IDAuMTQsIHRpcC5sZW5ndGggPSAwLjAyKSArCiAgbGFicyhjb2xvcj1OVUxMKSsKICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZSA9ICJEYXJrMiIpICsKICBwbG90X3NlbGVjdG9yKCJwb2ludHMiKSArCiAgYXBwbHlfdGV4dF9mb3JtYXR0aW5nICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwgbGVnZW5kLmRpcmVjdGlvbiA9ICJob3Jpem9udGFsIikgKwogIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChuY29sID0gMikpCgpwbHRfc2ltaWxhcml0eSA8LSBtdWx0aV9kaWFnbm9zaXNfc2ltaWxhcml0eV9oZWF0bWFwKAogIG1ldGhvZCA9ICJicmF5IiwKICBzaG93X2RlbmQgPSBGLAogIGxlZ2VuZF9sYWJlbCA9ICJCcmF5LUN1cnRpcyBzaW1pbGFyaXR5IiwKICBsZWdlbmRfZGlyZWN0aW9uID0gImhvcml6b250YWwiLAogIGxhYmVsX3NpemUgPSA2LAogIHRpdGxlX3NpemUgPSA5LAogIGRmX2dwdDMuNV9pY2QsCiAgZGZfZ3B0NC4wX2ljZCwKICBkZl9jbGF1ZGUzX2hhaWt1X3QxLjBfaWNkLAogIGRmX2NsYXVkZTNfb3B1c190MS4wX2ljZCwKICBkZl9nZW1pbmkxLjBfcHJvX3QxLjBfaWNkLAogIGRmX2dlbWluaTEuNV9wcm9fdDEuMF9pY2QKKQoKZnVsbF9wbHQgPC0gcGxvdF9ncmlkKAogIAogICMjIwogIHBsdF9kaWFncywKICAjIyMKICBOVUxMLAogIHBsb3RfZ3JpZCgKICAgICAgZ3JpZDo6Z3JpZC5ncmFiRXhwcihDb21wbGV4SGVhdG1hcDo6ZHJhdyhwbHRfc2ltaWxhcml0eSwgaGVhdG1hcF9sZWdlbmRfc2lkZSA9ICdib3R0b20nKSksCiAgICAgIHBsdF9yYW5rLAogICAgICAjIE5VTEwsCiAgICAgIHBsb3RfZ3JpZCgKICAgICAgICBwbG90X2dyaWQoCiAgICAgICAgICBwbHRfc2hhbm5vbisgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIiksCiAgICAgICAgICBwbHRfcHJlY2lzaW9uKyB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSwKICAgICAgICAgIG5yb3cgPSAxLAogICAgICAgICAgYXhpcyA9ICd0YicsCiAgICAgICAgICBhbGlnbiA9ICdoJywKICAgICAgICAgIGxhYmVscyA9IGMoTEVUVEVSU1s0OjVdKQogICAgICAgICksCiAgICAgICAgZ2V0X2xlZ2VuZChwbHRfc2hhbm5vbisgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKHJvdyA9IDEpKSksCiAgICAgICAgbmNvbCA9IDEsCiAgICAgICAgcmVsX2hlaWdodHMgPSBjKDEsMC4xKQogICAgICApLAogICAgICBucm93ID0gMSwgCiAgICAgICMgcmVsX3dpZHRocyA9IGMoMSwgMC4wMSwgMC44LCAwLjkpLAogICAgICByZWxfd2lkdGhzID0gYygwLjgsIDEsMC45KSwKICAgICAgbGFiZWxzID0gYyhMRVRURVJTWzI6M10pLAogICAgICB2anVzdCA9IDAuMgogICAgKSwKICBuY29sID0gMSwKICByZWxfaGVpZ2h0cyA9IGMoMS4yLCAwLjA1LCAwLjY1KSwKICBsYWJlbHMgPSBjKCJBIiwiIiwiIikKKSAgCgpmdWxsX3BsdApgYGAKCgpUaGluZ3MgdG8gZml4Ci0gTGVnZW5kIHBvc2l0aW9uIGZvciBDLUUKLSBMZWdlbmQgd2lkdGggZm9yIEIKLSBNb3ZlIGxlZ2VuZCBmb3IgQSB0byB0aGUgbGVmdCBvZiAiRnJlcXVlbmN5PyIKLSBSYW5rIHBsb3QgbGluZSB3ZWlnaHQKCmBgYHtyfQpnZ3NhdmUocGxvdD1mdWxsX3BsdCxmaWxlbmFtZT1oZXJlKCJmaWd1cmVzLzNfZGlhZ25vc2lzX2RpdmVyc2l0eS5wZGYiKSwgd2lkdGggPSA3LjUsIGhlaWdodCA9IDcuNSkKYGBgCgpzZXRfdGFibGVfcHJvcGVydGllcyhvcHRzX3BkZiA9IGxpc3QodGFiY29sc2VwID0gMCkpCmBgYHtyfQpzZXRfZmxleHRhYmxlX2RlZmF1bHRzKGZvbnRzX2lnbm9yZT1UUlVFKQoKbXVsdGlfZGlhZ25vc2lzX3JhbmtfdGFibGUoc2VhcmNoX3BhdHRlcm4gPSAiVDc4XFwuMiB8RDQ3XFwuMDIgfEQ4OVxcLjQxIHxEODlcXC40OSB8RDg5XFwuNCAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRmX2dwdDMuNV9pY2QsIGRmX2dwdDQuMF9pY2QsIGRmX2NsYXVkZTNfaGFpa3VfdDEuMF9pY2QsIGRmX2NsYXVkZTNfb3B1c190MS4wX2ljZCwgZGZfZ2VtaW5pMS4wX3Byb190MS4wX2ljZCkgJT4lIAogIGZsZXh0YWJsZSgpICU+JSAKICB3aWR0aCh3aWR0aCA9IDIpICU+JSAKICBmb250c2l6ZShzaXplID0gOSkgJT4lIAogIGZvbnRzaXplKHNpemUgPSAxMCwgcGFydCA9ICJoZWFkZXIiKSAlPiUgCiAgcGFkZGluZyhwYWRkaW5nID0gMCkgJT4lIAogIGFsaWduKGogPSAyOjMsIGFsaWduID0gImNlbnRlciIsIHBhcnQgPSAiYWxsIikgJT4lIAogIHNldF90YWJsZV9wcm9wZXJ0aWVzKG9wdHNfcGRmID0gbGlzdChhcnJheXN0cmV0Y2ggPSAxLjI1KSkgJT4lIAogIHtwcmludCguLCBwcmV2aWV3ID0gInBkZiIpOy59CmBgYAoKCg==